Embedded System에 사용되는 메모리 MAP 방식에 관한 연구


[한빛미디어] 2004-10-21 11:22 / 조회수 2,201

저자: 임영규 / GNOME Linux 연구소 imlinux70@hanafos.com
 

 
1. 서론

최근 임베디드 시스템에 대한 열기와 유비쿼터스에 대하여 많은 미디어를 통하여 실감할 수 있다. 이번 연구에서는 임베디드 시스템에서 사용하는 메모리 접근 제어 방식에 대하여 기술한다. 실제 임베디드 시스템을 이용한 개발 모델을 수행하는 과정에서 꼭 이해하여야 하는 중요한 이론중의 하나라고 볼 수 있다. 흔히 임베디드 시스템은 메모리를 I/O Device와 연결을 함에 있어 메모리를 매핑(Memory mapping)시켜 사용한다. 이러한 메모리 매핑 방법에서는 표준 C Library에서 제공하는 mmap 함수를 이용하는 방법과 직접 메모리 세그먼트와 오프셋을 포인터로 연결하는 방식을 사용한다. 따라서 다음과 같이 두 가지의 방식을 사용한다.

- 임메디드 시스템의 메모리 접근 방법

        1. mmap 함수를 이용하는 방법
        2. 메모리 직접제어 방식


2. 본론

임베디드 시스템에 사용하는 메모리 접근 방식에 대하여 하나씩 살펴보고 이것을 C 언어 코드와 함께 살펴보기로 한다.

2.1 mmap을 이용한 제어

mmap 함수를 이용하는 방법은 우선 mmap함수의 몸체를 살펴 볼 필요가 있다. 다음은 mmap함수의 선언부분이다.


#include
void * mmap(void *start, size_t length, int prot , 
          int flags, int fd, off_t offset);

int munmap(void *start, size_t length);


mmap함수는 start부터 length까지의 메모리 영역을 열린 파일 fd에 대응한다. 대응할 때 파일의 위치를 지정할 수 있는데 이것은 offset을 통해서 이루어진다. prot는 파일에 대응되는 메모리 영역의 보호특성을 결정하기 위해서 사용된다. 메모리영역과 파일이 서로 대응되기 때문에 파일에 대한 어떠한 작업이 메모리영역에 직접적인 영향을 미칠 수 있기 때문이다. prot는 다음과 같은 플레그(flag)를 제공한다.


PROT_EXEC 페이지(page)는 실행될 수 있다.
PROT_READ 페이지는 읽혀질 수 있다.
PROT_WRITE 페이지는 쓸 수 있다.
PROT_NONE 페이지를 접근할 수 없다.


mmap를 사용할 때 반드시 MAP_PRIVATE와 MAP_SHARED둘중 하나를 사용해야 한다.


#include
#define IO_BASE_ADDR 0x30000000 
#define U32 unsigned int
#define U16 unsigned short
#define IO_SIZE  0xff

U32 *base_addr;
U16    data;
int      fd;
fd = open( "/dev/mem", O_RDWR|O_SYNC );
if( fd < 0 )
{
perror( "/dev/mem open error" );
exit(1);
}

// map alloc
base_addr = 
     mmap (0, PROT_READ|PROT_WRITE, MAP_SHARED, fd, IO_BASE_ADDR );

// put the data
*base_addr=0x1234;
// get the data
data = *base;
/* other code here */
munmap( baseaddr, IO_SIZE ); // map release
close( fd );


2.2 volatile 키워드를 사용하는 방식

메모리의 특정 영역을 특정 장치와 연결하여 사용하는 방법입니다. 임베디드 시스템에서 가장 흔한 예가 제어 레지스터와의 메모리 매핑이 되겠다. 그 이외에도 많은 장치(플래시, LCD, 터치 스크린)들을 이러한 식으로 사용될 수 있다. 만약 임베디드 시스템에서 특정 제어 레지스터에 값을 설정한다고 가정한다면 이 방법으로 사용할 수 있다. 물론 값을 얻어 오기 위해서도 사용할 수 있다. 이런 경우의 예제를 살펴보면 다음과 같다.


volatile U16 *addr=0x00;

// put data
*addr =0xf0;
*(addr+0x555) =0xaa;
*(addr+0x2aa) =0x55;
*(addr+0x555) =0x90;

// get data
data1=*addr;
data2 =*(addr + 0x01);


위의 예제에서 특정 장치와 memory map된 주소에 데이터를 쓰는 경우에는 다음과 같은 간단한 매크로를 사용 할 수 있다.


#define AMD_CMD(addr, data) *( (volatile U16 *) addr) = (U16)(data);

/* some code :: put data into memory */
AMD_CMD(0x3000000, 0x1234);


컴파일러는 volatile 키워드가 선언된 변수에 대해서는 무조건 메모리에 접근하여 됩니다. 이러한 memory-mapped I/O 이외에도, 쓰레드 등으로 프로그램을 만들어서 공유변수를 한쪽에서 읽고, 한쪽에서 쓰는 경우도 해당될 수 있으며, 시스템 시간과 같이 특정 위치의 변수 값이 자신과는 독립적으로 계속 변하는 경우에도 사용할 수 있다.


3. 결론

두 방식에 대하여 메모리를 직접 제어하는 방법에 대하여 알아보았다. 파일 I/O와 함께 mmap 함수를 사용하는 경우와 volatile 키워드를 사용한 메모리 직접 제어 방식에 대하여 각각 예를 통하여 살펴보았다. 임베디드 시스템을 이해하고 프로그래밍 함에 있어 꼭 필요한 것은 사실이다. 따라서 이러한 제어 방식에 대하여 충분히 이해를 하고 임베디드 시스템 프로그래밍을 작성하여야 한다. 위 논문은 앞으로 ARM 코어 칩을 사용하는 CPU와 기타 장치의 적적한 제어 과정에 사용될 아주 기본적인 지식이다. 향후 이러한 방식을 직접 적용하여 LCD, 플래시 메모리, Uart(시리얼 통신)을 제어하는데 도움이 될 것이다.
신고
블로그 이미지

꽃중년

불만있으면 떠나라...

티스토리 툴바