본문으로 바로가기
728x90
반응형

 임베디드 시스템을 위해 펌웨어를 작성할 때 일반적인 소프트웨어 작성하듯 하다 보면 낭패를 격게 되는 경우가 종종 있다. 이번에 내가 고생한 부분을 하나 이야기 하면서 다른 분들은 그러지 않기를 바란다.

 이전 포스팅에서도 적었지만 오랜만에 Atmega를 사용하게 되었다. 원래 내가 주로 사용하는 MCU는 siliconlab사의 C8051을 주력으로 사용하는데 이번 프로젝트는 고객사에서 Atmega를 사용해 다라고 하여서 오랜만에 프로그램을 하게 되었다.

 C8051에 대해서는 다른 포스팅에서 다룰 것이긴 한데 내 개인적인 견해로는 8bit MCU 중 좋은 편이다. 성능이나 유동성에 있어서 다른 MCU보다 좋다. 여튼 원래 8051을 사용하면서는 문제가 없었던 일이 또 발생하였는데 이번에는 통신에서 발생하였다. 통신에서 수신이 완료되어 인터럽트를 처리 후 인터럽트 루틴 안에서 전역 변수 플래그를 셋하고 나와 메인에서 처리를 하는데 이 전역 변수 플래그가 제대로 안되는 것이었다. 

 아놔....이걸로 정말 엄청 고생했는데 문제되는 부분을 찾을 수가 없었다. 또다시 구글님의 힘을 빌어 열심히 검색 결과...이럴 수가 인터럽트 사용하는 전역 변수는 volatile 처리를 하라고 하더라.....8051하면서는 사용할 일이 없던 volatile.......결국 이 처리를 하고 나서 정상적으로 통신 처리가 되니 화도 났지만 나의 기억력 또는 무지에 허탈감 까지 느껴졌다.

 volatile.....뜻으로 말할 거 같으면 '휘발성의' 모 이런 뜻이다. 즉, volatile로 지정된 변수는 휘발성으로 인식되어 RAM에 저장하고 컴파일러가 컴파일시 최적화 구문에서 제외시킨다. 이게 왜 중요하냐면 MCU 펌웨어를 하다보면 직접 레지스터에 접근하여 설정하는 경우가 많은데 가령,

 *(unsigned int*)0x8000 = 0xDE;  
 *(unsigned int*)0x8000 = 0xAD;

 이러한 구문이 있다고 하면 8000번지에 결국 0xAD로 설정되게 되므로 0xDE로 만드는 구문을 컴파일러가 최적화 하면서 무시하는 경우가 있다. 그러나 실제 MCU 제어에서는 0xDE 설정 후 0xAD를 해야 하는 경우가 있다. 컴파일러의 최적화가 되면 이런 코드가 무시가 되면서 실제 동작에는 이상이 생기고 디버깅시 발견하기 힘든 에러가 발생할 수 있다.

 *(volatile unsigned int*)0x8000 = 0xDE;  
 *(volatile unsigned int*)0x8000 = 0xAD;

그리고 MCU의 경우 인터럽트에 의해 이 변수가 변경될 수 있는 가능성이 있기 때문에 실제 코딩 구문에서는 변화가 없을 지라도 외부 요인에 의해 변화가 생길 수 있는데 이를 컴파일러가 최적화 무시를 하는 경우가 있다. 이러면 나의 경우와 같이 변수가 변경이 안되는 상황이 발생할 수도 있다. 결론적으로 

 1) 메모리 맵핑

 2) 인터럽트

 이 두가지에 사용하는 변수 같은 경우는 volatile로 지정하여 컴파일 최적화를 하지 않게 해 주어야 한다.

728x90
반응형