Embedded 실습/AT91SAM7S256

ADC(Analog-to-Digital Converter) 사용하기 - 4

중동콜링 2013. 5. 1. 22:17

ADC에 전원공급을 했으니 이제 타이밍 다이어그램을 참고하여 ADC를 이용하여

LCD에 출력할 수 있는 ADC_run()함수를 구현해보자.


위의 다이어그램은 특정 레지스터에 특정 값이 들어왔을 때 ADC_SR레지스터의 EOCx비트와 DRDY비트가 변화하는 것을 보여준다.

좌측과 우측의 ①, ②, ③은 모두 동일하나 ④에서 다른 모습을 보여준다.


① ADC_CR의 START 비트를 1로 설정하면 ADC에서 값을 읽어오는  ② Conversion Time이 시작된다.

Conversion Time이 완료되면 ③에서 처럼 ADC_SR레지스터의 EOCx와 DRDY비트가 HIGH로 설정되는데

④ ADC_CDRx 레지스터를 읽을 경우 EOCx의 값은 LOW로 내려가지만 DRDY의 값은 변화가 없다.

하지만 ④에서 처럼 ADC_LCDR의 값을 읽어올 경우 EOCx와 DRDY 모두 LOW로 바뀌는 것을 알 수 있다.


이제 각 레지스터들의 기능을 알아본다.


위의 표에서 타이밍 다이어그램에서 보았던 레지스터들의 기능을 알 수 있다.

ADC_CR : 컨트롤 레지스터

ADC_SR : 상태 표시 레지스터

ADC_LCDR : 마지막에 값이 변한 핀을 알려주는 레지스터

ADC_CDR0~7 : 8개의 ADC 핀을 각각 지정한 레지스터


ADC_CR은 32비트중 첫 두비트만 사용하는 것을 알 수 있다.

0번 비트는 리셋을 해주는 비트고

1번 비트는 1로 세팅했을 때 아날로그-디지털 변환 시작을 지시한다.

#define ADC_CR   (*((volatile unsigned int *)0xFFFD8000)) // Control Register :546P

#define START 1

    ADC_CR = 1 << START;

위 코드는 ADC_CR레지스터의 스타트 비트인 1번째 비트에 1을 대입해주는 코드이다


ADC_SR 레지스터는 이름대로 상태를 표시하는 레지스터인데

그 중 EOC0~7 비트는 0~7번핀의 아날로그-디지털 변환이 끝났음을 알려주고

DRDY비트는 ADC_SR의 16번째 비트이며, 0~7번핀중 하나라도 값이 변했을 경우 사용가능함을 알리는 비트이다.

DRDY비트는 ADC_LCDR이 데이터를 읽어오면 값이 다시 초기화 된다.

#define ADC_SR   (*((volatile unsigned int *)0xFFFD801C)) // Status Register

#define DRDY 16
#define EOC0 0
#define EOC1 1
#define EOC2 2
#define EOC3 3
#define EOC4 4
#define EOC5 5
#define EOC6 6
#define EOC7 7

    while(0 == ADC_SR & (1 << DRDY)); // 값이 바뀔때 까지 delay 목적: conversion time 대기

위 코드는 ADC_SR의 DRDY비트가 1로 바뀔때 까지,

즉 컨버전 타임이 끝날때 까지 대기해주는 코드이다.


ADC_LCDR은 아날로그-디지털 변환이 끝난 데이터가 이 레지스터에 저장되며 

다시 아날로그-디지털 변환이 처리될 때 까지 그 데이터가 남아있게 된다.

만약 ADC_LCDR에서 데이터를 읽어올 경우 ADC_SR레지스터의 DRDY비트와 EOCx비트가 모두 Low로 클리어된다.


#define ADC_LCDR (*((volatile unsigned int *)0xFFFD8020)) // Last Converted Data Register

    return (ADC_LCDR & 0x3FF);

위의 코드는 LCDR레지스터의 값에 0~9비트이상을 0으로 클리어 해준 후

그 값을 리턴해주는 코드이다. 

즉, 0000 0000 0000 0000 0000 0011 1111 1111로 AND연산을 해주므로써 

0~9비트까지는 원래의 값을 보존하고 그 이상의 비트는 모두 0으로 클리어 해준다.

오동작을 방지하기 위한 코드이다.


ADC_CDR0~7는 0~7번핀 중 해당 핀에 아날로그-디지털 컨버팅이 끝난 데이터가 입력되는 레지스터다.

ADC_CDR0~7 레지스터에서 데이터를 읽어올 경우 ADC_SR레지스터의 EOCx비트만 Low로 클리어 된다.


다음은 define문을 이용하여 레지스터와 비트의 값을 지정해 놓은 adc.h 헤더파일이다.

#ifndef _ADC_H_
#define _ADC_H_

#define ADC_CR   (*((volatile unsigned int *)0xFFFD8000)) // Control Register :546P
#define ADC_MR   (*((volatile unsigned int *)0xFFFD8004)) // Mode Register
#define ADC_CHER (*((volatile unsigned int *)0xFFFD8010)) // Channel Enable Register
#define ADC_CHDR (*((volatile unsigned int *)0xFFFD8014)) // Channel Disable Register
#define ADC_CHSR (*((volatile unsigned int *)0xFFFD8018)) // Channel Status Register
#define ADC_SR   (*((volatile unsigned int *)0xFFFD801C)) // Status Register
#define ADC_LCDR (*((volatile unsigned int *)0xFFFD8020)) // Last Converted Data Register
#define ADC_IER  (*((volatile unsigned int *)0xFFFD8024)) // Interrupt Enable Register
#define ADC_IDR  (*((volatile unsigned int *)0xFFFD8028)) // Interrupt Disable Register
#define ADC_IMR  (*((volatile unsigned int *)0xFFFD802C)) // Interrupt Mask Register
#define ADC_CDR0 (*((volatile unsigned int *)0xFFFD8030)) // Channel Data Register 0
#define ADC_CDR1 (*((volatile unsigned int *)0xFFFD8034)) // " 1
#define ADC_CDR2 (*((volatile unsigned int *)0xFFFD8038)) // " 2
#define ADC_CDR3 (*((volatile unsigned int *)0xFFFD803C)) // " 3
#define ADC_CDR4 (*((volatile unsigned int *)0xFFFD8040)) // " 4
#define ADC_CDR5 (*((volatile unsigned int *)0xFFFD8044)) // " 5
#define ADC_CDR6 (*((volatile unsigned int *)0xFFFD8048)) // " 6
#define ADC_CDR7 (*((volatile unsigned int *)0xFFFD804C)) // Channel Data Register 7

#define PMC_PCER (*((volatile unsigned int *)0xFFFFFC10)) // Peripheral Clock Enable Register P.200
#define ADC_ID 4

#define SWRST 0 // ADC_CR P.547
#define START 1

#define CH0 0
#define CH1 1
#define CH2 2
#define CH3 3
#define CH4 4
#define CH5 5
#define CH6 6
#define CH7 7

#define LIGHT CH4

#define LOWRES 4 // 0 : 10 bit, 1 : 8 bit resolution
#define PRESCAL 8 // 분주비

#define DRDY 16
#define EOC0 0
#define EOC1 1
#define EOC2 2
#define EOC3 3
#define EOC4 4
#define EOC5 5
#define EOC6 6
#define EOC7 7

void ADC_init();
unsigned int ADC_run();

#endif // _ADC_H_


아래 함수는 타이밍 다이어그램 대로 작성하여

ADC를 통해 센서의 값을 읽어 올 수 있는 ADC_run()함수의 본체이다.


unsigned int ADC_run()
{
    ADC_CR = 1 << START;

    // 16번째 비트 DRDY값만 추출 : BIT MASK 0101 & 0100 = 0100
    while(0 == ADC_SR & (1 << DRDY)); // 값이 바뀔때 까지 delay 목적: conversion time 대기

    // 10bit 이상을 0으로 클리어
    return (ADC_LCDR & 0x3FF);
}