Presentation is loading. Please wait.

Presentation is loading. Please wait.

Lecture 18: ADC Implementation Lecturers: Professor John Devlin.

Similar presentations


Presentation on theme: "Lecture 18: ADC Implementation Lecturers: Professor John Devlin."— Presentation transcript:

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

2 Overview Using a MAX1111 Using the internal ADC 2

3 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

4 MAX1111 Architecture 4

5 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

6 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

7 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

8 Track and Hold Circuits Holds input voltage constant for the conversion period. 8

9 MAX1111 – SAR ADC Successive Approximation Block Performs Binary search Uses REFIN as the reference voltage Supplies result to output shift register 9

10 MAX1111 - Circuit 10

11 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

12 MSP430 ADC – Internal View 12

13 #include #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 – Code LED Temp increase display

14 #pragma vector=SD16_VECTOR __interrupt void SD16ISR(void) { if (SD16MEM0 <= LastADCVal + ADCDeltaOn) P1OUT &= ~0x01; else P1OUT |= 0x01; LastADCVal = SD16MEM0; } // Watchdog Timer interrupt service routine #pragma vector=WDT_VECTOR __interrupt void watchdog_timer(void) { SD16CCTL0 |= SD16SC; } MSP430 ADC – Code LED Temp increase display Interrupt routines

15 MSP430 ADC – Circuit Diagram MSP430F2013 1K 4.7K 3.3V A4: P1.1 15

16 MSP430 ADC – Code RESET MOV.W #0280h,SP ; Set stackpointer (128B RAM device) stopWDT MOV.W #WDTPW+WDTHOLD,&WDTCTL ; Stop watchdog timer setupP1 MOV.B #11111101b,&P1DIR ; Set P1.0 -> P1.7 as outputs, P1.1 as input BIS.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 + modulation setupADC MOV.W #0000000011010100b,&SD16CTL ; SMCLK, Ref On MOV.W #0001000000000010b,&SD16CCTL0 ; Unipolar, Start conversion MOV.B #00000100b,&SD16INCTL0; A4 (connected to P1.1) 16

17 MSP430 ADC – Code MOV.W #0FFFFh, R7 init MOV.W #04h, R6; AND SD16CCTL0, R6; Mask out other bits to get SD16IFG JNZ read_adc ; ADC conversion completed init2 MOV.W R7, R4 XOR.B #01h, &P1OUT; Toggle Pin main DEC R4 JNZ main JMP init read_adc MOV.W &SD16MEM0, R7; Read ADC value from MEM0 JMP init2 17

18 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

19 19

20 // 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 // Header file for this device #include // Intrinsic functions #include // Standard integer types #defineLED_OUTP1OUT_bit.P1OUT_0// Output to LED on P1.0 #defineLED_ANALOGSD16AE_bit.SD16AE0// Enable analog input from LED #defineRANGE4096// Dynamic range of values from SD16 #define PWM_MAX128// Maximum value of duty cycle #defineDIVISOR(RANGE/PWM_MAX)// For converting SD16 -> PWM #defineSENSE_TIME2// 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 watchdog BCSCTL1 = CALBC1_8MHZ;// Calibrated range for DCO DCOCTL = CALDCO_8MHZ;// Calibrated tap and modulation BCSCTL2 = DIVS_3;// SMCLK = DCO / 8 = 1MHz BCSCTL3 = LFXT1S_2;// Select ACLK from VLO (no crystal) P2SEL = 0;// Digital i/o rather than crystal P2REN = BIT6|BIT7;// Pull Rs on unused pins (6 and 7) P1REN = ~BIT0;// Pull Rs on all pins except 0 P1DIR = BIT0;// To drive LED on P1.0 LED_OUT = 0;// LED initially off (active high) // Configure SD16A: clock from SMCLK, no division, internal reference on SD16CTL = SD16XDIV_0 | SD16DIV_0 | SD16SSEL_1 | SD16REFON; // Unipolar, single convs, OSR = 32, interrupts on finish SD16CCTL0 = SD16UNI | SD16SNGL | SD16OSR_32 | SD16IE; // PGA gain = 16, input channel A0+/-, result after 4th conversion SD16INCTL0 = SD16GAIN_16 | SD16INCH_0 | SD16INTDLY_0; // Timer_A for software-assisted PWM using channel 1, up to TACCR0 mode TACCR0 = PWM_MAX + SENSE_TIME;// Overall period TACCR1 = dutyCycle;// Initial duty cycle TACCTL1 = CCIE;// Interrupts on compare // Start Timer_A from ACLK, undivided, up mode, clear, interrupts TACTL = TASSEL_1 | ID_0 | MC_1 | TACLR | TAIE; for (;;) {// Loop forever __low_power_mode_3();// All action in interrupts } 20

21 //---------------------------------------------------------------------- // 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 int case 0:// No interrupt pending break;// No action case TAIV_TAIFG:// TAIFG vector // Start PWM duty cycle by turning LED on and updating duty cycle LED_OUT = 1;// Turn LED on; duty cycle always > 0 TACCR1 = dutyCycle;// Update duty cycle from SD16 reading break; 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 LED LED_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: ignore break; } //---------------------------------------------------------------------- // 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 output if (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

22 //****************************************************************************** // 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

23 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 buffer unsigned 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

24 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

25 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); }

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

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


Download ppt "Lecture 18: ADC Implementation Lecturers: Professor John Devlin."

Similar presentations


Ads by Google