728x90

임베디드 시스템에서 입출력 장치 접근

1. 디바이스 드라이버 사용하는방법

 - 디바이스 데이터 입출력 기능과 디바이스 제어하는 기능

 - 디바이스에 대한 공통 인터페이스(파일 인터페이스)를 통해 모든 디바이스에 유사한 방법으로 접근

2. 물리 어드레스를 통해 직접 접근하는 방법

 - 운영체제 안쓰는 경우 디바이스 물리 어드레스맵으로 물리어드레스를 알수있슴

 - 리눅스 경우 메모리 디바이스 파일을 이용해 물리 어드레스 공간에 접근

 -> 물리 어드레스로 디바이스 제어를 위해 디바이스 동작과 제어 방법을 이해해야함

 

(1) 입출력 장치 제어 방법

1) 임베디드 시스템 정의

2) 가상주소를 이용한 접근

 

1) 입출력 장치 제어

입출력 장치 접근방법

1. 물리 어드레스 사용한 접근

 - 가상 어드레스를 물리 어드레스로 변경하는 전용함수로 입출력 장치 접근

2. 디바이스 드라이버 사용한 간접 접근

 - 운영체제서 제공하는 디바이스 드라이버로 간접적으로 접근

 

입출력 장치 제어 프로그램 구현 방법

1. 물리 어드레스 사용한 접근

 - 가상 메모리 변환 함수 사용

2. 디바이스 드라이버 사용한 간접 접근

 - 커널에 디바이스 드라이버 모듈 등록

=> 사용자 응용 프로그램 특성에 따라 입출력 제어방식 선택

 

입출력 장치 어드레스 매핑 방식

1. Memorry Mapped IO

 - 입출력 장치와 메모리가 동일한 주소체계

 - 프로세서는 입출력 장치도 메모리 처럼취급

 -> 다양한 메모리 접근 명령어들을 입출력 장치에 동일하게 사용가능

 <-> 메모리 공간이 줄어듬

2. IO Mapped IO

 - 메모리 주소체계와 입출력 장치 주소체계를 분리해서 사용

 - 입출력 전용 명령어 및 전용 주소 체계 사용

 -> 메모리 공간 손실 없음

 <-> 입출력 전용 명령어 필요

=> 대부분 32비트 프로세서는 Memoery Mapped IO 사용

 

가상 어드레스 Virtual Address

- 리눅스 커널 내부에서 사용하는 논리적 어드레스 체계

- 메모리 관리 시스템 MMU을 사용하여 물리 어드레스와 가상 어드레스 변환

- TLB Translation Looaside Buffer

  1. MMU 내부에 존재

  2. 물리 어드레스 또는 가상 어드레스로 변환시 참조하는 테이블

  3. 응용프로그램에서 사용하는 가상 어드레스는 TLB를 사용해 물리 어드레스로 변환되어 메인 메모리를 직접 액세스

  4. 대부분 32비트 프로세서는 Memory mapped io 사용

   -> TLB를 통해 가상 어드레스만으로 입출력 장치를 직접 액세스

 

포인터를 사용한 데이터 전송

- 응용프로그램에서 입출력 장치에 데이터 전송하는것은 포인터 변수에 물리 어드레스줘 데이터를 쓰고읽으며 이루어짐

* 리눅스 커널에서 물리적 접근을 허가하지 않기 때문에 아래의 경우 오류가 발생 -> 가상주소를 사용해야함

unsigned int *ptr;
ptr = 0xf1000000;	//물리주소 할당
*ptr = 0xc0;		//포인터를 사용한 데이터 쓰기

2) 가상주소를 사용한 접근

메모리 디바이스

- 메모리 디바이스 파일 /dev/mem

  -> 시스템 메모리 공간에 접근할수 있는 장치파일

- 메인 메모리의 이미지를 가진 문자형 디바이스

- 주로 시스템 테스트 용도로 사용

- 입출력 장치를 직접접근하는 디바이스로 활용

 

응용 프로그램에서 특정 물리 어드레스 접근

- 가상 어드레스 획득 : mmap()함수

1. 입출력 장치의 가상어드레스 획득

2. 어드레스에 대한 읽기 쓰기 작업 실행

3. 입출력 장치와 데이터 전송

- 데이터 읽기쓰기 : 메모리 장치 디바이스를 통한 lseek(), read(), write()함수 사용

 

mmap 함수 사용

- 파일이나 디바이스를 메모리로 매핑시켜주는 함수

- 반환값 : 주어진 물리주소에 해당하는 가상주소값

 

응용 프로그램 코드에서 "mmap()" 함수 사용절차

1. mmap() 호출

2. 커널은 내부적으로 mmap() 함수 파라미터를 해석하여 매핑 영역 설정

3. 그 위치에 해당하는 가상주소를 계산하여 반환

4. 응용프로그램에서는 반환된  가상주소를 포인터 변수에 대입

5. 포인터 변수에 값을 할당하거나 변수 값을 읽어 데이터 전송

 

2)munmap()

- munmap() - mmap() : par 함수

- mmap으로 맵핑된 메모리 해제

- 형식

#include <unistd.h>
#include <sys/mman.h>
int munmap(void *start, size_t length);

- 파라미터

  start : mmap()에서 반환했던 가상주소를 대입하여 해제할 매핑영역 전달

  length : 해제할때 영역의 길이를 byte 단위로 계산하여 대입

- 성공시 0 실패시 -1 반환

 

munmap() 실행에 따른 오류반환값

1. EBADF : fd가 유효하지 않거나 MAP_ANONYMOUS가 설정되지않음

2. EACCES : MAP_PRIVATE가 설정되어있지만, fd가 못쓰는 경우

3. EINVAL : starrt나 length나 offest 이 적당하지 않음, 너무크거나 PAGESIZE 경계로 정렬되지 않음

4. EAGAIN : 파일이 잠겨있거나 너무 많은 memory가 잠김

 

mmap/munmap 함수사용하는 방법

1. open()함수로 파일 디스크립터 획득

2. mmap()함수로 제어할 IO 포인터 획득

3. 포인터로 값을 읽거나 원하는 값을씀

4. munmap() 함수로 매핑한 메모리 공간 해제

5. close()함수로 오픈한 파일디스크깁터 반환

 

간단한 LED 제어

#include <unistd.h>
#include <sys/mman.h>

#define ADDR_LED 0x00a1111

fd = open("/dev/mem",O_RDWR);
addr= mmap(NULL,1,PROT_WRITE,MAP_SHARED,fd,ADDR_LED);
//1바이트를 메모리에 매핑, 매핑 영역에 대한 쓰기 권한 허용, 다른프로세서에서 쓸수있도록 매핑공유
*addr=0xaa;
munmap(addr,1);
close(fd)

간단한 전체 프로그램

#include <unistd.h>
#include <sys/mman.h>
#include <asm/fcntl.h>

int main()
{
	int fd;
    unsigned int *maddr, *ptr;
    if (((fd=open("/dev/mem", O_RDWR)) < 0) exit(1);
    
    maddr=mmap(NULL, 1024, PROT_WRITE, MAP_SHARED, fd, 0xf0000000);
    if ((int)maddr <0) return -1;
    ptr = maddr;
    ptr= ptr+68;
    *ptr=0x1000401;
    ptr++;
    *ptr=0xf10080000;
    munmap(maddr,1024);
    close(fd);
    return (0);
}
300x250

+ Recent posts