Input/Output Control
목 차 I/O Control Mechanism RAM Area Access LED Control 목 차 I/O Control Mechanism mmap function munmap function RAM Area Access LED Control 4 digits 7 Segment Control Text LCD Control
I/O Control Mechanism (1) Device Control Physical Address Control: application program Device Driver: kernel program 디바이스 프로그램 구현 방법 커널의 디바이스 드라이버 모듈 등록 가상 메모리 접근에 의한 구현 사용자의 응용 프로그램 특성에 따라 device control 방식을 선정 가상주소(Virtual address) 실제 존재하는 물리 주소가 아니라, Linux kernel 내부에서 일정한 단계를 거쳐 논리적으로 계산된 다른 주소체제
I/O Control Mechanism (2) 응용 프로그램에서 특정번지 액세스 pointer 변수를 이용하여 해당 register의 address에 원하는 데이터를 write하는 programming 예제) 물리 주소: 0xf100 0000, 데이터: 0xc0 unsigned char *ptr; ptr = 0xf100 0000 /* register physical address */ *ptr = 0xc0 /* write data value to register */ 오류 발생: Linux kernel 에서 물리적 접근을 허가하지 않음, 가상주소를 사용
mmap()을 이용한 I/O Control 메모리 장치 디바이스 /dev/mem : 시스템의 memory 공간에 접근할 수 있는 장치파일 응용 프로그램에서 특정 physical address에 접근 memory 장치 디바이스를 통한 lseek(), read(), write() 함수 이용 memory 장치 디바이스를 통한 mmap() 함수 이용 mmap 함수 열린 파일 기술자(file descriptor)를 통해 access되는 파일의 내용과 관련된 memory 의 구역에 대한 pointer를 생성 file이나 device driver 메모리에 mapping시키는 함수
가상 주소 액세스 : mmap() 응용 프로그램 코드에서 memory mapping을 구현하는 방법은 “mmap( )” 함수 호출 mmap() 함수는 파라메터(argument)에서 제공된 특정 대상 메모리에 mapping한 후에 mapping 된 지점에 해당되는 가상주소를 반환하는 함수 mmap()이 호출되면, 프로그램 제어권이 Linux kernel로 이관, Linux kernel은 내부적으로 mmap() 함수 인자를 해석하여 mapping 영역을 설정하고 그 위치에 해당하는 가상주소를 계산하여 mmap()으로 반환 반환된 가상주소에 pointer 변수에 대입
mmap() function (1) mmap 함수의 원형 Arguments start: 특정 memory address를 요청하기 위해, 일반적으로 0으로 설정 length: memory segment의 길이 설정 port: memory segment를 위한 액세스 허용 권한 설정 flags: page에 가해지는 변경이 다른 곳에 반영되는 방법 설정 fd: 파일 기술자 offset: 파일 데이터의 시작을 변경 mapping 대상의 시작 위치를 제시하며, mapping 대상의 내용 가운데 이 지점부터 memory 를 mapping void *mmap (void *start, size_t length, int prot, int flags, int fd, off_t offset);
mmap() function (2) Protection mode Flag parameters PROT_EXEC: page execution PROT_READ: page read 허락 PROT_WRITE: page write 허락 PROT_NONE: page access 불가 Flag parameters MAP_FIXED: 특정한 mapping 위치로 고정 MAP_SHARED: 다른 프로세스와 mapping 영역의 공유가 가능 MAP_PRIVATE: mapping을 설정한 자신만의 mapping 영역의 사용이 가능
Example of mmap() Program example Header files “start” argument fd = open(“/dev/mem”,O_RDWR); addr = mmap(NULL,1,PROT_WRITE,MAP_SHARED,fd,ADDRESSOFLED); *addr = 0xaa; munmap(addr,1); close(fd) Header files #include <unistd.h> #include <sys/mman.h> #ifdef _POSIX_MAPPED_FILES “start” argument mapping 영역이 시작되길 원하는 위치를 의미하며, 통산 null 혹은 0값으로 대입을 권고 0값이 아닌 경우 flag 인자가 MAP_FIXED 일때 mapping 영역의 시작 위치가 이 값이 되도록 커널에서 강제적으로 요청할 경우에 사용 일반적으로 mapping 의 시작 위치는 자동적으로 비어 있는 영역을 커널로 선택하도록 하는 것이 안전하므로 null 혹은 0값으로 대입
munmap() function mmap 함수와 함께 쓰며, mmap으로 메핑된 메모리를 반환 mumap 함수 원형 open() 함수를 사용하여 열린 file descriptor를 획득한다. mmap() 함수를 사용하여 제어할 I/O의 pointer 획득한다. pointer에서 값을 읽거나 원하는 값을 쓴다. munmap() 함수를 사용하여 memory 공간 해제한다. close() 함수를 이용하여 열린 descriptor를 반환한다. int munmap (void *start, size_t length);
munmap() usage(1) 형식 Argument munmap() Return value munmap() mmap()과 pair 함수 Memory mapping을 해제하는 기능 형식 #include <unistd.h> #include <sys/mman.h> int munmap (void *start, size_t length); Argument Start: mmmap()에서 반환했던 가상주소를 대입 함으로서, 해제할 mapping 영역을 공지 Length: 해제할 때 영역의 길이를 byte 단위로 계산하여 대입 munmap() Return value Success: return (0) Fail: return (-1)
munmap() usage(2) munmap() 실행에 따른 오류 반환값 EBADF: fd가 유효한 파일 기술자가 아니다. 즉MAP_ANONYMOUS가 설정되어 있지 않다. EACCES: MAP_PRIVATE가 설정되었지만, fd가 읽을 수 있도록 열려있지 않다. 또는 MAP_SHARED와 PROT_WRITE가 설정되었지만, fd가 쓸 수 있도록 열려있지 않다. EINVAL: start나 length나 offset가 적당하지 않다. 즉 너무 크거나 PAGESIZE 경계로 정렬되어 있지 않다. ETXTBUSY: MAP_DENYWRITE가 설정되었으나, fd로 지정된 객체가 쓰기 위해 열려있다. EAGAIN: 파일이 잠겨있거나, 너무 많은 memory가 잠겨있다. ENOMEN: 사용할 수 있는 메모리가 없다.
가상메모리 접근 절차 예제 0xff00 0000부터 1,024바이트 크기에 해당하는 물리적 주소영역을 mmap()에 의해 메모리 mapping을 시도하며, 그때 얻어진 가상주소에 의해 간단한 포인터 연산을 한 후에 mapping 영역을 해제 접근 절차 mmap()의 인자로 사용될 mapping 의 대상 선정: fd(장치 디바이스 혹은 파일) 매핑 대상(디바이스)에 대한 open mmap() 호출: 목적에 맞는 인자 설정 메모리 mapping 이 성공적으로 완료되며, 해당 할당 mapping 메모리의 pointer를 접근하여 데이터를 접근 원하는 연산이 종료되어 더 이상 mapping 영역이 필요 없는 경우에는 munmap()으로 해제
Example of mmap() (1) #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <asm/fcntl.h> int main() { int men_fd; unsigned long *men_add32, *ptr; if((mem_fd=open(“/dev/mem”, O_RDWR)) < 0){ perrpr(“mem open fail\n”); exit(2); } mem_addr32=mmap(NULL, 1240, (PRO_READ| PROT_WRITE), MAP_SHARED, mem_fd, 0xff00 0000); if((int men_add32 < 0) { mem_addr32 = NULL; printf(“mmap error\n”); return -1;
Example of mmap() (2) wrtie_data () { ptr=mem_addr32; ptr=ptr+68; *ptr=0x1000 0401; ptr++; *ptr=0xf100 8000; } release_function() mummap(mem_add32, 1024); return 0;
RAM Area Access Control SRAM 256Kbytes × 16 bits, 1Mbytes Hardware signal: PXA255 Chip Selection (CS) nCS3 – 0x0c000 0000 Diagram
RAM Area Access Program (1) RAM(0x0c00 0000)을 액세스하는 프로그램 코딩(readram) /dev/mem mmap( , , , , , 0x0c0000000) mumap() Boot loader 상에서 0x0c00 0000 번지의 데이터 확인(read) 및 “1234568”을 write read b32 0x0c000000 a write b32 0x0c000000 12345678 Linux booting 및 RAM access 프로그램 수행 EMPOS # boot # ./readsram sram_val: 12345678
RAM Area Access Program (2) 1. SRAM 하드웨어 번지를 정의 : (prgram name: readram) #define ADDRESSOFSRAM 0x0c00 0000 2. 가상번지를 저장할 변수를 저장하고, open 함수로 fd 설정 unsigned long *addr_sram; fd=open(“/dev/mem",O_RDWR|O_SYNC)) 3. mmap 함수를 이용하여 SRAM 영역의 가상번지를 획득 addr_sram = mmap(NULL,1,PROT_READ,MAP_SHARED,fd,ADDRESSOFSRAM); 4. 얻은 번지의 내용을 확인하는 코드 삽입 printf("sram_val:[%x]\n",*addr_sram); 5. Makefile을 작성하여 컴파일 CC = arm‐linux‐gcc readsram: readsram.c $(CC) $(CFLAGS) ‐o $@ $^ clean:rm ‐f readsram 6. 확인된 내용이 정확한가를 bootloader에서 재확인 EMPOS # read b32 0x0c000000 a 7. 로더에서 SRAM 영역에 값을 넣은 후 다시 한번 확인 EMPOS # write b32 0x0c000000 12345678 ;; bootloader에서 해당번지에 데이터를 입력 EMPOS # boot ;; linux booting # ./readsram ;; linux에서 해당 번지의 RAM을 접근 sram_val:12345678
LED Control (1) 8개 SMD 형태의 LED로 구성: 8bit(1 byte) write 구조 특정번지(0x1060 0000)에서 데이터 bit를 출력으로 LED를 on/off 제어 fd=open(“/dev/mem”, O_RDRW|O_SYNC) led_addr=mmap(NULL, 1, PROT_WRITE, MAP_SHARED, fd, 0x10600000) led_light{ …. *led_addr =0xaa, delay-fector() ….} munmp(led_addr, 1); 회로
LED Control (2) LED Register: 0x1060 0000, 8bits
7 segment Control (1) 4개의 7segment LED로 구성된 write 구조 회로 4개의 7segment는 8개의 출력 bit로 구성 32bit CPU 제어를 위해 2개의 7segment 단위(16bits)로 제어 7segment LED 정보 지속을 위해 latch 구조 회로 7segment_low =0x1030 0000 7segment_low =0x1040 0000
7 segment Control (2) Code 1: 0bc0 0000 2: ab0d e0g0 BCD-to-7segment Decoder Activate signal: positive, negative Display: 0-1 figures Code 1: 0bc0 0000 2: ab0d e0g0 a b c d e f g dp
7 segment LED Data: Cathode type Cathode type: active High Table Program char GetSegcode(char x) { … switch(x) ….. } 표시 7 세그먼트 비트 값 데이터 값 dp g f e d c b a 1 0x3f 0x06 2 0x5f 3 0x4f 4 0x66 5 0x6d 6 0x7d 7 0x27 8 0x7f 9 0x6f
7segment Program (1) Header file #define segment7_L 0x10300000 #define segment7_H 0x10400000 void Showsegment(unsigned int highValue, unsigned int lowValue) addr_lseg=mmap(NULL,4,PROT_WRITE, MAP_SHARED, fd, segment7_L); addr_hseg=mmap(NULL,4,PROT_WRITE,MAP_SHARED, fd, segment7_H); *addr_lseg = lowValue; *addr_hseg = highValue; munmap(addr_lseg, 4); munmap(addr_hseg,4); int sizeofword(char *word) char Getsegcode(char x){ … switch(x) ….. }
7segment Program (2) int main() { int k; unsigned int low = 0,high = 0; char data[5]; strcpy(data,"0000"); k = sizeofword(data); switch(k) { case 1: low = Getsegcode(data[0]); break; case 2: low = Getsegcode(data[0]); low = (low<<8) | Getsegcode(data[1]); break; case 3: high = Getsegcode(data[0]); low = Getsegcode(data[1]); low = (low<<8) | Getsegcode(data[2]); break; case 4: high = Getsegcode(data[0]); high = (high<<8) | Getsegcode(data[1]); low = Getsegcode(data[2]); low = (low<<8) | Getsegcode(data[3]); break; default : break; } showsegment(high, low); exit(0); }
Experiment of 4 digits Counter 4 digit의 7segment LED를 이용하여 counter program을 코딩 사용자가 키 ‘r’을 누르면, 7segment 카운터가 시작 사용자가 키 ‘s’를 누르면, 7segment 카운터가 일시 정지 사용자가 키 ‘c’를 누르면, 정지했던 7segment 카운터를 계속 진행 사용자가 키 ‘q’를 누르면, 7segment 카운터 프로그램 종료
I/O Program Coding에서 Device Driver/IO control Program 형태에 따른 분류 단방향(Read or Write)과 양방향(Read/Write) Character, Block, Stream, File 직렬, 병렬(단위에 따라 1-4bytes로 구분) 주변 디바이스 접속에 따른 분류: network, I/O, PCIbus, Buffer 등 Device Driver 설계시 유의사항 하드웨어에 대한 해박한 지식: 회로도 이해, 해당 디바이스 드라이버를 구현될 보드와 소자/CHIP set에 대한 이해 디바이스 드라이버 적용 방법 설정: 가상 메모리 접속, 커널 I/O 모듈 디바이스 드라이버를 사용하는 응용 서비스의 특성에 부합성 참고문헌 김인성, 류태중, “Linux Device Drivers”, 한빛미디어, 2000.
Text LCD module Text LCD Signals: 14 pins 최대 가로로 쓰여지는 문자 수와 세로로 표시되는 줄 수로 규격 열과 행을 구동하는 LCD driver와 이를 제어하는 LCD controller로 구성: Text LCD모듈은 8bit microprocessor가 내장되어 있고, 2개의 레지스터가 존재 202(4), 162(4), 242(4), 142(4) size Signals: 14 pins Data: byte, DB0 – DB7 Control: R/W, RS (Register Select), E (Enable) Power: GND (Vss), Vcc, Vo (LCD contrast) Signals (pin) Display (back light)
Text LCD module 제어 방법 Text LCD를 사용방법 Text LCD 모듈 접속회로 설계방법 Text LCD Registers Instruction Register (IR) : Text LCD 모듈의 환경설정 Data Register (DR) : Text LCD 모듈에 글자를 표시하기 위한 데이터 값이 들어가는 레지스터 Text LCD를 사용방법 Instruction Register (IR)에 명령을 set Data Register (DR)에 표시하고자 하는 데이터 값을 write Text LCD 모듈 접속회로 설계방법 Text LCD의 data line은 8bit, control bit가 3bit이므로 디바이스 드라이버에서는 하위 8bit는 data line으로 묶고, 상위 3bit는 control line(R/W, RS, E)으로 사용
Text LCD Functions 4/8/32 bits microprocessor와 인터페이스 디스플레이 dot resolution: 58, 510 dots 808 bits의 display data RAM: Display Data RAM에 최대 80 문자 저장 가능) 240 문자 font 를 위한 문자 발생기 ROM(Character Generator ROM) 648 bits 문자 발생기 CG RAM DC 5 volt 단일 전원과 LCD Contrast Control Power LCD LCD segment Driver Instruction Register(IR) Data Register(DR) IN/OUT Buffer Microprocessor Interface RS R/W E D0 D7 5 V GND RS=0 RS=1
Text LCD Block Diagram Block diagram
Text LCD Registers Data Register (DR) DD(display data) RAM 혹은 CG(character generator) RAM에 write를 위한 데이터를 저장하거나, DD RAM 혹은 CG RAM에서 Read된 데이터가 일시적으로 저장 CPU로부터 DR에 써 넣은 데이터는 LCD의 내부 동작에 의해 DD RAM, CG RAM에 자동적으로 Write LCD로부터 데이터를 읽기 위해서 address 정보를 IR에 써 넣으면, DD RAM 혹은 CG RAM으로 부터 DR에 내부적인 동작에 의해서 자동 저장되고, DR에 저장된 데이터가 CPU로 읽어지게 됨. Instruction Register (IR) CPU로부터 LCD 표시에 관련된 제어명령을 쓰거나, LCD 모듈의 제어상태를 확인하는 용도 LCD 화면 Clear, 커서 shift, 글자 On/OFF 등의 LCD 제어 명령정보를 저장 DD RAM과 CG RAM의 표시를 위한 address 정보 저장
Instructions Clear Display: 전체 화면을 지우고 어드레스 카운터를 DD RAM(Display Data RAM) address를 0으로 하여 커서를 home으로 위치한다. Return Home: DD RAM의 내용은 변경하지 않고 커서를 home위치로 한다. Entry Mode Set: 데이터를 read하거나 write할 경우에 커서의 위치를 증가(I/D=1)시킬 것 인가 감소(I/D)시킬 것 인가를 결정하며, 또한 화면을 Shift 할 것인지(S=1) 아닌지(S=0)를 결정한다. Display On/Off control: 화면 표시를 On/Off 하거나(D), 커서를 On/Off 하거나(C), 커서를 깜빡이게 할 것인가(B) 여부를 지정한다. Cursor or Display Shift: 화면(S/C=1) 또는 커서(S/C=0)를 오른쪽(R/L=1) 또는 왼쪽(R/L=0)으로 shift한다. Function Set: 인터페이스에서 데이터의 길이를 8비트(DL=1) 또는 4비트(DL=0)으로 지정하고, 화면 표시 행수를 2행(N=1) 또는 1행(N=0)으로 지정하며, 문자 폰트를 5x10 dot(F=1) 또는 5x7 dot(F=0)로 지정한다. Set CG(Character Generator) RAM Address: CG RAM의 어드레스를 지정한다. 이후에 송수신하는 데이터는 CG RAM 데이터이다. Set DD(Display Data) RAM Address: DD RAM의 어드레스를 지정한다. 이후에 송수신하는 데이터는 DD RAM 데이터이다. Read Busy Flag and Address: LCD 모듈이 내부 동작 중임을 나타내는 Busy Flag(BF) 및 어드레스 카운터 내용을 read 한다.
Text LCD I/F Circuit Circuit
Register Section Register 선택: RS, R/W signal 사용 RS R/W action 1 - IR 선택, 제어명령 쓰기(display clear, etc) 1 - DB7로부터 Busy Flag를 읽기 - address counter를 DB0-DB6으로 읽기 - DB 선택하여 데이터 값을 쓰기(DR에서 DD RAM CG RAM으로) - DB 선택하여 데이터 값을 읽어오기(DD RAM/ CG RAM에서 DR로)
setcommand Void secommand (unsigned short command) function RS=0, R/W=0 : IR selection and write instruction data value E=0 : E=low/E=high/E=low ---> activation b10=E, b9=R/W, b8=RS 0 0 0 xxxx xxxx 1 0 0 xxxx xxxx 0 0 0 xxxx xxxx
BF, AC, DD RAM (1) Busy Flag (BF) Address Count (AC) DD RAM 연속적으로 LCD 모듈에 제어명령이 입력될 때 LCD 모듈이 처리할 수 있는 가를 나타내는 상태 플래그 BF=0, 다음 명령 가능(RS=0, R/W=1, BF 값은 DB7으로 출력), BF=1 제어 명령 불가 Address Count (AC) DD RAM, CG RAM에 address를 할당, 1개의 명령 address가 IR에 써질 때, address 정보는 IR에서 AC로 전송 DD RAM 8비트 문자 코드에 상응하는 디스플레이 데이터를 저장, 용량은 88 bit로 80 character 20문자2line인 경우 DD RAM address
BF, AC, DD RAM (2) DD RAM address Text LCD base address: 0x1070 0000 DDRAM address = base address + 1st/2nd column address
CG ROM, CG RAM CG ROM CG RAM 8bit 문자 코드로부터 208개의 57 혹은 32개의 5 10 dot의 문자 패턴을 발생 CG RAM 사용자가 프로그램으로 문자 패턴을 설계 57 dot는 8종, 510 dot는 4종을 생성
Text LCD Control Functions(1) Clear display Cursor Return home Entry Mode Set Display ON/OFF Control Cursor Display Shift Function Set: Initialization CG RAM Address Set, DD RAM Address Set Busy Flag/Address Read CG RAM/DD RAM으로 데이터 Write와 Read 제어 신호: RS, R/W, DB0-DB7, E
Text LCD Control Functions(2) Control function & Instruction Mode/Code 기 능 제어신호 제어 명령 실행시간 RS R/W D7 D6 D5 D4 D3 D2 D1 D0 Clear Display 1 1.64ms Return Home Entry Mode Set I/D S 40us Display On/Off control D C Cursor or Display Shift S/C R/L Function Set D/L N F Set CG RAM Address CG RAM Address Set DD RAM Address DD RAM Address Read Busy Flag and Address BF Address Counter 0us Data Write to CG RAM or DD RAM Write Address Data Read to CG Read Address
Read Timing Diagram R/W 신호가 인가된 후, E 신호가 activate 된 후에 40ns 후에 data line에 valid data 신호가 인가 Active edge
Write Timing Diagram Write Timing Code b10=E, b9=R/W, b8=RS 0 0 1 0 0 1 1 0 1
Text LCD 모듈 초기화 전원을 공급한다. LCD 모듈이 Reset 되려면, 대략 50ms가 소요된다. “Function set” 명령(0x001x xx00)을 보낸다. “display ON/OFF control” 명령(0x0000 1xxx)을 보낸다. “Entry mode set” 명령(0x0000 01xx)을 보낸다. DD RAM 주소를 보낸다. 문자 데이터를 연속으로 보낸다. ---------------- Control bit RS, R/W, E는 Text LCD timing diagram에 맞추어 제어
Text LCD Program (1) #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <asm/fcntl.h> #include <stdio.h> #define ADDRESSOFTEXTLCD 0x10700000 void setcommand(unsigned short command); void initialize_textlcd(); void writebyte(char ch); void write_string(char *str,int length); int function_set(int rows, int nfonts); int display_control(int display_enable, int cursor_enable, int nblink); int cusrsor_shit(int set_screen, int set_rightshit); int entry_mode_set(int increase, int nshift); int return_home(); int clear_display(); int set_ddram_address(int pos); unsigned int *pTextlcd;
Text LCD Program (2) int main(int argc, char **argv) { int fd; int i, len1=11,len2=19; char buf1[100] = "Wellcome to"; char buf2[100] = "the Embedded World!"; if(argc == 2) { len1 = strlen(argv[1]); len2 = 0; strcpy(buf1,argv[1]); }else if(argc >= 3) { len2 = strlen(argv[2]); strcpy(buf2,argv[2]); } if ((fd=open("/dev/mem",O_RDWR|O_SYNC)) < 0){ perror("mem open fail\n"); exit(1); pTextlcd=mmap(NULL,4,PROT_WRITE, MAP_SHARED, fd, ADDRESSOFTEXTLCD); if((int)pTextlcd < 0){ pTextlcd=NULL; close(fd); printf("mmap error\n"); return ‐1; initialize_textlcd(); for(i=0;i<len1;i++) writebyte(buf1[i]); set_ddram_address(0x40); for(i=0;i<len2;i++) writebyte(buf2[i]); munmap(pTextlcd,4); close(fd); }
Text LCD Program (3) Initialization Screen erase Cursor control
Experiment 교재 p.227 실습 내용을 수행 Text가 흐르는 광고판 만들기 왼쪽으로 10초 간격으로 문장이 천천히 shift: (1행) “호남대학교를 사랑합니다” (2행) “우리의 목표는 최고의 임베디드 시스템 엔지니어가 되는 것” “s” 키보드를 누르면, 다시 시작 “x” 키보드를 누르면, 프로그램 종료