본문으로 바로가기

ATmega8 OSCCAL 레지스터 사용하기

category MicroProcessor/AVR 2012.03.09 00:33


내부 8MHz 설정으로 사용하면서 USART를 사용하기 전까지는
시스템 클럭의 정확성에 대한 의문이 들면서도 잘 작동해서 크게 문제 삼지 않았다.

USART로 통신을 하면서 자꾸 통신 중간에 오류가 발생하는 것을 보면서
이런 저런 해결책을 찾던 중에 문제는 내부 RC 오실레이터가 정확하지 않다는
것을 알게 되었고 내부 오실레이터를 보정해서 정확도를 올릴 수 있다는 것을 알았다.

ATmega8은 1,2,4,8MHz의 4가지 주파수를 내부 RC 오실레이터의 주파수로 설정할 수 있는데
공장 출하되는 장치는 기본 1MHz로 동작하도록 OSCCAL에 값을 자동으로 넣는다고 한다.

이때, 1,2,4,8MHz의 주파수가 +-1% 오차 범위내에 있도록 하는 보정 값이 미리 시그니처 바이트가
위치한 메모리 상위 바이트에 저장되어 있다고 한다.

사용하려는 주파수는 8MHz이므로 OSCCAL에 들어 있는 값이 8MHz를 위한 보정 값이 아니므로
8MHz에 대한 보정값을 OSCCAL에 넣어야 하는데 어렵게 생각했는데 그리 어렵지는 않았다.

직접 보정값을 읽어내는 방법은 어려워 보여서 ISP를 이용해서 읽어낸 후에 이를 EEPROM 특정
위치에 저장하고 리셋 후에 바록 읽어 들여서 OSCCAL에 저장하는 방법을 선택하였다.

윤교수님의 홈페이지에 있는 stk500 호환 isp를 제작해서 사용했는데
AVR Studio에서 ISP를 실행 후에 avr prog 버튼을 눌러서 프로그래머 창을 띄운 후에
HW setting를 설정하는 탭에서 8MHz에 대한 OSCCAL 값을 얻었다.

avr freak 사이트에서 검색하면서 보던 값인 0xA9을 얻었다.

이것을 EEPROM의 가장 뒷쪽에 저장(512바이트의 크기이므로 끝 주소:0x1FF)하였다.

AVR-GCC를 사용하기 때문에 eeprom을 다루기 위해서
<avr/eeprom.h>를 인클루드하고 아래의 코드를 넣었더니 아주 잘 작동했다.

eeprom_busy_wait();
OSCCAL = eeprom_read_byte((uint8_t *)0x1FF);

eeprom을 다룰 때는 항상 eeprom에 접근가능한가를 확인해야 하는데
eeprom_busy_wait()를 호출해서 이 동작을 행한다.

512바이트의 eeprom의 가장 뒷 쪽에 캘리브레이션 값을 저장했기 때문에 0x1FF에서 1바이트를
가져다가 OSCCAL에 저장하는 동작이 전부이다.


댓글을 달아 주세요