본문 바로가기

About/Embedded System

[Embedded] volatile 선언(하드웨어 폴링과 volatile)

임베디드 시스템에서는 주기적으로 하드웨어를 감시해 상태가 변한 것을 감시하는 처리가 빈번히 실행된다. 이 처리를 폴링(polling)이라고 한다. 인터럽트 기능을 갖고 있지 않은 주변장치 등을 감시하기 위해 사용된다.

간단하게 말해서 폴링은 "프로그램이나 장치에서 다른 프로그램이나 장치들이 어떤 상태에 있는지를 지속적으로 검사하는 전송 제어 방식"이다.

Polling의 예시

이 때 주변장치의 감시를 위해 레지스터 주소를 지정한 처리를 작성했다고 하면, 컴파일러는 주변장치의 레지스터 주소를 알지 못하기 때문에 최적화 옵션을 지정하여 컴파일하면 의도하지 않은 상황으로 전개될 가능성이 있다.

이 때 volatile 선언으로 최적화를 하지 않도록 지정한다.

 


for(;;){
	if((*(unsigned long*)(0x0000000F)) & 0x04){
	// 수신이 완료되면
    	수신 처리
        break;
    }
}

위의 코드는 for 루프 안의 if 문에서 레지스터 주소를 체크하여 수신했는지를 판정한다.

 

하지만 위의 코드가 컴파일러에서 최적화되면

if((*(unsigned long*)(0x0000000F)) & 0x04){
    // 수신 완료되면
    for(;;){
        //수신 처리
        break;
    }
}

if 문이 for 루프 밖으로 나가 한 번밖에 실행되지 않는다.

 

따라서 volatile 선언을 이용하여 최적화를 억제하여야 한다.

for(;;){
    if((*(volatile unsigned long*)(0x0000000F)) & 0x04){
        // 수신완료되면
        수신 처리
        break;
    }
}

 

 


또 다른 예시를 살펴보면

static int foo;

void bar(void)
{
    foo = 0;

    while (foo != 255);
}

위의 코드에서 foo 값이 초기값 0 이후 while 루프 안에서 foo 값이 변하지 않아 while의 조건은 항상 true이다.

따라서 컴파일러는 다음과 같이 최적화한다.

 

void bar_optimized(void)
{
    foo = 0;

    while (true);
}

이렇게 되면 while의 무한 루프에 빠지게 되고 volatile을 사용하여 최적화를 방지할 수 있다.

 

static volatile int foo;

void bar (void)
{
    foo = 0;

    while (foo != 255);
}

 

이렇게 되면 개발자가 의도한 대로, 작성한 대로 기계어 코드가 생성된다. 위 프로그램은 무한루프라고 생각할 수 있지만 foo가 하드웨어 장치의 레지스터라면 하드웨어에 의해 값이 변할 수 있다.

 


따라서 volatile 선언은 하드웨어  값을 폴링할 때 사용할 수 있다.