본문 바로가기
전자/임베디드 시스템

AVR 프로그래밍

by Begi 2019. 3. 10.
반응형

AVR 구조 - 하바드 아키텍츠

AVR은 하바드 구조 (Harvard Architecture)를 가지고 있다. 하바드 구조는 프로그램 메모리와 데이터 메모리가 분리되어 있는 구조이다. 그래서, AVR에서 프로그램을 작성할 때는 하바드 구조가 아닌 CPU에서 프로그램 할 때와 조금 다른 특성이 있다.

 

하바드 구조에서는 프로그램과 데이터 영역이 분리되어 있기 때문에 상수로 선언된 변수를 사용하기 위해서는 상수가 저장된 플래시 메모리에서 데이터 메모리를 이동해야 한다. 변수를 상수로 선언하면 일반적인 CPU에서는 플래시에 변수가 할당되지만 AVR에서는 플래시와 램 모두를 사용한다. AVR에서 PROGMEM는 플래쉬에 저장된 데이터를 엑세스하기 위한 명령어로 플래시 메모리에서 램을 사용하지 않고 직접 엑세스하기 위한 명령어이다.

 

하바드 구조에서는 함수의 포인터 주소와 변수의 포인터 주소가 전혀 다른 영역을 나타낸다.

 

AVR 변수 크기

AVR ATmega 컴파일에 많이 사용되는 avr-gcc에서는 윈도우 기반의 PC와 변수의 크기가 다르다. PC에서는 int가 4 byte 지만 AVR에서는 2 byte 이므로 프로그램 작성시 주의해야 한다.

   char         1 byte
   short        2 byte
   int          2 byte
   long         4 byte
   long long    8 byte

 

AVR에서 상수 데이터를 플래시에 저장하는 방법

AVR에서는 변수를 const로 선언해도 데이터가 RAM에 할당된다. AVR에서 상수 데이터를 플래시를 저장하기 위해서는 PROGMEM을 사용해야 한다.

 

PROGMEM을 사용하는 기본적인 방법은 다음과 같다.

 #include <avr/pgmspace.h>  // include를 한다


 char data[10] PROGMEM = {0,1,2,3,4,5,6,7,8,9}; // 상수 데이터를 설정


 // 상수 데이터를 사용
 b0 = pgm_read_byte (&data[0]);
 b1 = pgm_read_byte (&data[1]);
 b2 = pgm_read_byte (&data[2]);


 // 상수 데이터의 포인터를 얻기 위해서는 PGM_P를 사용한다.
 p0 = (PGM_P)pgm_read_byte (&data[0]);

 

16비트 데이터는 pgm_read_word를 사용한다. data[0]을 바로 읽으면 에러 메세지는 뜨지 않지만 쓰레기 값이 읽히기 때문에 주의해야 한다. 

 

AVR에서 상수가 플래시에 저장되지 않는 않는 이유는 AVR은 하바드 구조를 가지고 있기 때문이다.

 

printf 사용

AVR에서 시리얼 포트를 이용하여 printf를 출력하기 위한 방법은 다음과 같다. 

 

 
// 1. 헤더파일
#include <stdlib.h>
#include <std.h>


// 2. FILE
FILE *fp;
// 3. UART 초기화void UART_Init(int BaudRate){  UBRR0H = ((SYSTEM_CLOCK/BaudRate/16)-1)/256;
  UBRR0L = (SYSTEM_CLOCK/BaudRate/16)-1;  UCSR0A = 0x00;  UCSR0B = 0x98;  UCSR0C = 0x06;}
 
// 4. UART 추력함수 (UART0 인 경우)
int uart_putchar(char c)
{  if (c == '\n')
    uart_putchar('\r');  loop_until_bit_is_set(UCSR0A, UDRE0);  UDR0 = c;  return 0;

}
 
// 5. Main
int main(void){  UART_Init(9600);
  fdevopen(USART0_putchar,0,0);
  printf("Hello\n");
}

 

ATmega에서 AVRISP가 연결되지 않을 때

ATmega MCU를 사용 중 AVRISP가 연결 안될 때가 있다. 

 

AVRISP가 연결 안 되는 이유 중 하나는 SUT_CKSEL 퓨즈가 변경되었을 때이다. SUT_CKSEL은 ATmega의 클럭 소스를 설정하는 것으로 보도 상의 클럭 소스와 퓨즈 설정이 다르면 AVRISP가 연결이 되지 않는다.

 

ATmega의 클럭 소스는 내부 RC 클럭, 외부 RC 클럭, 크리스탈, 오실레이터의 4가지를 설정할 수 있다. 만약, 오실레이터로 퓨즈를 설정하고 실제 보드는 크리스탈이 달려 있다면 연결이 되지 않는다.

 

새 ATmega MCU의 디폴트 설정은 내부 RC 클럭을 사용한다.

 

이 때는 오실레이터 출력 핀을 ATmega의 XTAL1 핀에 점퍼선으로 연결한 후 AVRISP를 연결하고 보드에 맞는 클럭 소스를 퓨즈에 라이팅 하면 된다.

 

인터럽터 우선 순위

AVR은 Nested Interrupt를 MCU 차원에서 지원하지 않는다. Nested Interrupt는 사용자가 소프트웨어로 직접 구현해야 한다.

 

 

 

반응형

'전자 > 임베디드 시스템' 카테고리의 다른 글

GPIO 입력 포트 확장 IC  (0) 2019.10.25
임베디드 시스템 개발 과정  (0) 2019.07.09
Watchdog 프로그램에서 위치  (0) 2019.03.09
ATmega128 입출력 포트와 클럭  (0) 2018.10.12
Arbiter Circuit  (0) 2018.09.30

댓글