Embedded Lecture/Arduino2017. 3. 18. 16:33


AVR 칩을 사용하는 Arduino Uno 보드 혹은 다른 임베디드(Embedded) 시스템에서 전역 변수(globlal variable)는 주메모리인 SRAM에 저장되고, 지역 변수(local variable)는 레지스터(register) 영역에 저장됩니다. 그러나 인터럽트 서비스 루틴(ISR)에서의 지역 변수는 SRAM의 Stack 영역에 저장되므로 빠른 인터럽트 처리를 위해서 루틴 내에 잦은 지역 변수의 사용은 바람직하지 않다는 것입니다.


사용자의 코드를 컴파일러(Compiler)는 나름데로 최적화시키는데, 예를 들어 사용자가 전역 변수 지정을 하였지만 그 값이 시종일관 변하지 않는 변수는 컴파일러가 임의로 상수처럼 여겨 레지스터 영역에 저장하게 한다는 것입니다. 물론 한정된 레지스터 영역의 리소스를 낭비하는 것 아니냐고 생각할 수 있지만, 컴파일러 입장에서는 빠른 실행 속도를 위해서 SRAM 보다는 레지스터 영역에 저장한다는 것입니다.


그러나 임베디드 시스템의 경우에 인터럽트 서비스 루틴에서 전역 변수의 갱신이 있었다 하더라도, 컴파일러는 실제 런타임 시 처럼 외부에서 인터럽트가 걸리는 상황이 아니므로 그 값은 변하지 않는다고 생각하여 결국 레지스터에 저장하고 주메모리 상에 변경된 값의 반영이 없다는 것입니다.


이런 상황을 위해서 지시자(directive)인 'volatile'의 선언은 변수형 앞에 두어 컴파일러가 임의로 판단하여 그 변수를 레지스터에 할당하지 못하도록 한다는 것입니다. 즉, 어떤 변수를 volatile로 지정하면 그 변수는 레지스터의 임시 저장소가 아니라 SRAM에서 직접 읽어오도록 컴파일한다는 것입니다.


결론적으로 Arduino 코딩의 경우 보통은 volatile로 정의할 필요는 없으나 인터럽트 서비스 루틴 내부에서 그 값이 변경되는 변수는 반드시 volatile로 선언해야 실시간으로 변경되는 데이터 값을 ISR 루틴 외부에서 읽어올 수 있게 된다는 것입니다.


int pin = 13;

volatile int state = LOW;


void setup()

{

  pinMode(pin, OUTPUT);

  attachInterrupt(0, blink, CHANGE);

}


void loop()

{

  digitalWrite(pin, state);

}


void blink()

{

  state = !state;

}


위의 예제에서 blink() 함수는 인터럽트 서비스 루틴으로 0번 인터럽트 핀의 상태가 변할 때마다 13번에 연결된 LED를 교대로 점멸하게 됩니다. 만일 state 변수에 volatile 선언이 없었다면, 비록 blink() 함수 내에 state 값이 변하더라도 이 함수를 벗어나서는 state 값이 갱신되지 않기 때문에 0번 인터럽트의 상태 변화에 LED의 토글(toggle) 현상이 보이지 않는다는 것입니다.



'Embedded Lecture > Arduino' 카테고리의 다른 글

아날로그 입력 및 온도계 예제  (0) 2017.03.19
아날로그 입력  (0) 2017.03.18
아두이노의 TWI(I2C) 통신  (0) 2017.03.18
아두이노의 시리얼 통신  (0) 2017.03.18
인터럽트의 처리(1)  (0) 2017.03.12
Posted by Nature & Life