2016년 1월 27일 수요일

Arduino Uno에서 digitalWrite()와 직접 레지스터 제어의 속도 차이

먼저 아두이노 우노에서 가장 기본 예제인 blink를 실행시켜 출력파형을 오실로 스코프로 확인해 보면 다음과 같다.

void setup()
{
  pinMode(10, OUTPUT);
}

void loop()
{
  digitalWrite(10, HIGH);
  digitalWrite(10, LOW);
}



대략 digitalWrite()를 한번 실행하는데 6.8us정도의 시간이 걸린다.

위의 코드를 동일한 기능을 하지만 digitalWrite() 함수를 사용하지 않고 ATmega328의 레지스터를 직접 제어하도록 하면 코드는 다음과 같다.

void setup() { 
  DDRB |= (1<<2);}

void loop() {
  PORTB |= (1<<2);
  PORTB &= ~(1<<2);
}

위의 코드를 실행한 결과를 오실로 스코프로 확인한 결과는 다음과 같다.




이 경우 약 120ns정도의 시간이 걸리게 된다. (약 57배 speed up)
단 위의 파형에서 출력이 HIGH인 구간과 LOW인 구간이 비대칭인 이유는 loop함수를 빠져나갔다가 다시 호출되는데 필요한 오버헤드로 인해 LOW->HIGH구간에 포트 조작 이외의 작업이 추가되었기 때문이다.

void setup() { 
  DDRB |= (1<<2);}

void loop() {
  while (1) {
    PORTB |= (1<<2);
    PORTB &= ~(1<<2);
  }
}

코드를 위와 같이 수정하여 loop() 함수 exit/enter에 따른 오버헤드를 없애 준 결과는 다음과 같다.


아직도 아주 약간 비대칭이기는 해도 거의 차이가 없어진 걸 확인할 수 있다.

참고삼아 아래 코드를 실행해 측정해 본 digitalRead() 함수의 실행시간은 다음과 같다.

void setup() {
  DDRB |= (1<<2);
  pinMode(11,INPUT);
}

void loop()
{
  PORTB |= (1<<2); 
  boolean button = digitalRead(11);
  PORTB &= ~(1<<2);
}

digitalRead() 함수를 호출하는 경우 대략 5.2us 정도의 시간이 소요된다.