2009. 4. 23. 11:47
[AVR] DDRA, PORTA를 찾아보자.
2009. 4. 23. 11:47 in 공부합시다/임베디드
DDRA, PORTA는 도대체 어디에 정의되어 있을까?
헤더파일에서 직접 찾아보자.
소스코드를 보면 <stdio.h>처럼 많이 사용하는 io함수들을 사용하기 위해 아래와 같이 include한다.
#include <avr/io.h>
따라서 io.h를 살펴보면,
이라고 정의된 부분을 볼 수있다.
iom128.h를 찾아보자.(다른 MCU라면 해당 헤더파일을 찾으면 된다.)
imo128.h를 보면, (ctrl+f로 찾자)
이렇게 정의된 부분이 있다.
그렇다면, _SFR_IO8는 무엇일까.
아까 io.h를 다시 살펴보면,
#include <avr/sfr_defs.h> 라고 된 부분이 있다.
특수기능 레지스터에 대한 헤더파일인데, 이것을 열어보자.
이라고 된 부분을 보자.
이것은 매크로 함수인데, 뒷부분의 _MMIO...부분을 수행하는 것이다.
그렇다면 _MMIO_BYTE와 __SFR_OFFSET는 무엇일까.
sfr_defs.h에서 _MMIO_BYTE를 다시 찾아보면,
라고 정의된 부분을 찾을 수 있다.
volatile에 대해서는 여기를 참조하도록하자. <volatile 한정자 보기>
uint8_t는 unsigned 타입의 정수형(int) 8bit의 타입이라는 것이다.(이 부분이 정의된 부분은 아직 못찾았다.)
즉, unsigned char의 포인터형이란 뜻이고, 괄호가 되있으므로 캐스팅(형변환)을 하겠다는 뜻이다.
__SFR_OFFSET을 찾아보자.
마찬가지로 sfr_defs.h에 정의되어있다.
조건은 호환모드인가 노멀모드인가를 판별하는 것이고
그에 따른 값을 정의한다. 따라서, 노멀모드이므로 0x20이 된다.
즉, 0x3B주소지에서 1바이트 공간에 0xFF를 쓰겠다는 뜻이다.
그렇다면 0x3B는 무엇인가.
이는 atmega128의 스펙을 살펴봐야한다.
스펙을 살펴보면, PORTA 레지스터와 연결되어있음을 알수있다.
즉 0x3B에 데이터를 쓰게 되면 PORTA 레지스터에 데이터를 쓰는 것과 같은 것이다.
이를 활용하여 헤더파일을 작성할 수 있다.
헤더파일에서 직접 찾아보자.
소스코드를 보면 <stdio.h>처럼 많이 사용하는 io함수들을 사용하기 위해 아래와 같이 include한다.
#include <avr/io.h>
따라서 io.h를 살펴보면,
#elif defined (__AVR_ATmega128__)
#include <avr/iom128.h>
#include <avr/iom128.h>
이라고 정의된 부분을 볼 수있다.
iom128.h를 찾아보자.(다른 MCU라면 해당 헤더파일을 찾으면 된다.)
imo128.h를 보면, (ctrl+f로 찾자)
/* Input Pins, Port A */
#define PINA _SFR_IO8(0x19)
/* Data Direction Register, Port A */
#define DDRA _SFR_IO8(0x1A)
/* Data Register, Port A */
#define PORTA _SFR_IO8(0x1B)
#define PINA _SFR_IO8(0x19)
/* Data Direction Register, Port A */
#define DDRA _SFR_IO8(0x1A)
/* Data Register, Port A */
#define PORTA _SFR_IO8(0x1B)
이렇게 정의된 부분이 있다.
따라서 PORTA = 0xFF 라는 문장은,
_SFR_IO8(0x1B) = 0xFF 라고도 쓸수있다.
_SFR_IO8(0x1B) = 0xFF 라고도 쓸수있다.
그렇다면, _SFR_IO8는 무엇일까.
아까 io.h를 다시 살펴보면,
#include <avr/sfr_defs.h> 라고 된 부분이 있다.
특수기능 레지스터에 대한 헤더파일인데, 이것을 열어보자.
#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)
이라고 된 부분을 보자.
이것은 매크로 함수인데, 뒷부분의 _MMIO...부분을 수행하는 것이다.
따라서,
PORTA = 0xFF;
_SFR_IO8(0x1B) = 0xFF;
_MMIO_BYTE((0x1B) + __SFR_OFFSET) = 0xFF;
세문장은 모두 같은 문장이 된다.
PORTA = 0xFF;
_SFR_IO8(0x1B) = 0xFF;
_MMIO_BYTE((0x1B) + __SFR_OFFSET) = 0xFF;
세문장은 모두 같은 문장이 된다.
그렇다면 _MMIO_BYTE와 __SFR_OFFSET는 무엇일까.
sfr_defs.h에서 _MMIO_BYTE를 다시 찾아보면,
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
라고 정의된 부분을 찾을 수 있다.
따라서,
PORTA = 0xFF;
_SFR_IO8(0x1B) = 0xFF;
_MMIO_BYTE((0x1B) + __SFR_OFFSET) = 0xFF;
(*(volatile uint8_t *)((0x1B) + __SFR_OFFSET)) = 0xFF;
는 모두 같은 문장이 된다.
PORTA = 0xFF;
_SFR_IO8(0x1B) = 0xFF;
_MMIO_BYTE((0x1B) + __SFR_OFFSET) = 0xFF;
(*(volatile uint8_t *)((0x1B) + __SFR_OFFSET)) = 0xFF;
는 모두 같은 문장이 된다.
volatile에 대해서는 여기를 참조하도록하자. <volatile 한정자 보기>
uint8_t는 unsigned 타입의 정수형(int) 8bit의 타입이라는 것이다.(이 부분이 정의된 부분은 아직 못찾았다.)
즉, unsigned char의 포인터형이란 뜻이고, 괄호가 되있으므로 캐스팅(형변환)을 하겠다는 뜻이다.
__SFR_OFFSET을 찾아보자.
마찬가지로 sfr_defs.h에 정의되어있다.
#ifndef __SFR_OFFSET
/* Define as 0 before including this file for compatibility with old asm
sources that don't subtract __SFR_OFFSET from symbolic I/O addresses. */
# if __AVR_ARCH__ >= 100
# define __SFR_OFFSET 0x00
# else
# define __SFR_OFFSET 0x20
# endif
#endif
/* Define as 0 before including this file for compatibility with old asm
sources that don't subtract __SFR_OFFSET from symbolic I/O addresses. */
# if __AVR_ARCH__ >= 100
# define __SFR_OFFSET 0x00
# else
# define __SFR_OFFSET 0x20
# endif
#endif
조건은 호환모드인가 노멀모드인가를 판별하는 것이고
그에 따른 값을 정의한다. 따라서, 노멀모드이므로 0x20이 된다.
따라서,
PORTA = 0xFF;
_SFR_IO8(0x1B) = 0xFF;
_MMIO_BYTE((0x1B) + __SFR_OFFSET) = 0xFF;
(*(volatile uint8_t *)((0x1B) + __SFR_OFFSET)) = 0xFF;
(*(volatile uint8_t *)((0x1B) + 0x20)) = 0xFF;
(*(volatile uint8_t *)0x3B) = 0xFF;
PORTA = 0xFF;
_SFR_IO8(0x1B) = 0xFF;
_MMIO_BYTE((0x1B) + __SFR_OFFSET) = 0xFF;
(*(volatile uint8_t *)((0x1B) + __SFR_OFFSET)) = 0xFF;
(*(volatile uint8_t *)((0x1B) + 0x20)) = 0xFF;
(*(volatile uint8_t *)0x3B) = 0xFF;
즉, 0x3B주소지에서 1바이트 공간에 0xFF를 쓰겠다는 뜻이다.
그렇다면 0x3B는 무엇인가.
이는 atmega128의 스펙을 살펴봐야한다.
스펙을 살펴보면, PORTA 레지스터와 연결되어있음을 알수있다.
즉 0x3B에 데이터를 쓰게 되면 PORTA 레지스터에 데이터를 쓰는 것과 같은 것이다.
이를 활용하여 헤더파일을 작성할 수 있다.
'공부합시다 > 임베디드' 카테고리의 다른 글
[ATmega128] RS232 시리얼 통신 관련 레지스터 정리 (0) | 2009.04.28 |
---|---|
[ATmega1128] ATmega128은 Little endian일까 Big endian일까 (2) | 2009.04.24 |
Volatile 한정자 (0) | 2009.04.23 |
[DK-128] LED 순차적으로 점멸하기 (0) | 2009.04.22 |
[avr] 확장형 데이터 타입 (0) | 2009.04.22 |