FND 디바이스 드라이버 Lecture #11
차례 7-Segment FND 구동 원리 디바이스 드라이버 프로그램 시 필요한 함수 FND 디바이스 드라이버 fnd-driver.c FND 응용 프로그램 fnd-app.c FND 디바이스 드라이버 시험
Output Device – 발광다이오드(LED) LED(Light Emitting Diode) 화합물 반도체의 PN접합 다이오드로 양단에 전압의 차를 가하면 빛을 방출하는 발광소자 그림 (A)와 같이 2개의 다리가 나와있는데 긴 쪽이 애노드(+)이며 짧은 쪽이 캐소드(-)이다 약 2.5V정도의 전압차가 2개의 다리 양단에 걸리면 빛을 방출하는데, 보통 디지털소자의 출력이 5V이므로 그림 (B)와 같이 저항을 직렬로 연결하여 다이오드를 보호한다 그림 (A) 그림 (B)
Output Device – 7-Segment LED (1) FND 라고도 불리는데, 숫자나 문자를 표시하는데 사용되는 7개의 발광다이오드(LED)의 모임 공통 애노드(Common Anode) 형 : 다이오드의 애노드를 공통 단자로 사용한다 애노드 단자에 5V를 주고 캐소드의 각 단자 a~g 까지 0V를 주면 다이오드에 전류가 흐르게 되어 발광한다 다이오드의 파손 방지를 위해 저항을 연결 한다 Common Anode 형
Output Device – 7-Segment LED (2) 공통 캐소드(Common Cathode) 형 : 다이오드의 캐소드를 공통 단자로 사용한다 캐소드를 접지 시키고, 다이오드의 애노드 단자에 5V를 주면 전류가 흐른다 다이오드의 파손 방지를 위해 저항을 연결 한다 Common Cathode 형
Output Device – 7-Segment LED Array (1) Common Cathode 형 7-Segment LED 4 ARRAY 7-Segment LED 가 4개 병렬로 있는 것 공통단자가 캐소드형으로 com0, com1, com2, com3로 4개 있으며, 애노드 단자 a,b,c,d,e,f,g,dp는 공통으로 사용한다 LED를 제어하기 위한 전체 핀의 개수를 줄일 수 있는 장점이 있으나 컨트롤은 조금 복잡해진다
Output Device – 7-Segment LED Array (2) Common Cathode 형 7-Segment LED 4 ARRAY Com0=0, Com1=Com2=Com3=1인 경우, 입력 a,b,c,d,e,f,g중의 어느 하나가 1이면 가장 왼쪽에 해당되는 Segment LED가 발광한다
Output Device – 7-Segment LED Array (3) PXA255-FPGA Board – 7-Segment LED 6 Array
Output Device – 7-Segment LED Array (4) FND 포트의 물리 주소 0xC0000002 FND digit 및 segment 위치와 데이터 bit digit 부분(dig1~dig6)에는 0을, segment(a~dp) 부분에는 1을 write하면 주어진 digit의 segment에 불이 켜짐 보기) FND의 digit 3에 숫자 3(=segment abcdg)을 출력하려면 0xC0000002 번지에 0x4FFB을 출력하면 됨 FND dp g f e d c b a x dig6 dig5 dig4 dig3 dig2 dig1 bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
Output Device – 7-Segment LED Array (5) FND를 이용한 데이터 표현 예: Common Cathod 단자 Anode 단자
PXA255-FPGA – FND 회로 구성 (1)
PXA255-FPGA – FND 회로 구성 (2)
PXA255-FPGA – FND 회로 구성 (3)
PXA255-FPGA – FND 회로 구성 (4)
디바이스 드라이버 프로그램 시 필요한 함수 get_user(void *x, const void *addr) 사용자 영역의 *addr의 값을 커널 영역인 x로 sizeof(addr) 만큼 복사 put_user(void *x, const void *addr) 커널 영역의 *x의 값을 사용자 영역인 addr로 sizeof(addr) 만큼 복사 copy_to_user(void *to, void *from, unsigned long size) 커널 영역의 from에서 size 만큼을 사용자 영역의 to로 복사 copy_from_user(void *to, void *from, unsigned long size) 사용자 영역의 from에서 size 만큼을 커널 영역의 to로 복사 I/O로 부터 값을 읽는 함수 __u8 inb(unsigned int port) __u16 inw(unsigned int port) __u32 inl(unsigned int port) I/O에 값을 쓰는 함수 void outb(__u8 data, unsigned int port) void outw(__u16 data, unsigned int port) void outl(__u32 data, unsigned int port)
매크로/전역 변수 (fnd-driver.c) #define IOM_FND_MAJOR 241 // fnd device major number #define IOM_FND_NAME "fnds" // fnd device name #define IOM_FND_ADDRESS 0xC000002 // fnd physical address static int fnd_usage = 0; static int fnd_major = 0; static unsigned short *iom_fnd_addr; static unsigned short value_digit[6];static int WaitQ_count = 0; static struct file_operations iom_fnd_fops = { open: iom_fnd_open, write: iom_fnd_write, release: iom_fnd_release, }; static struct tq_struct Task = { { NULL, NULL }, 0, iom_fnd_display, (void *)&value_digit[0], DECLARE_WAIT_QUEUE_HEAD(WaitQ_fnd); //wait queue declare
init/cleanup (fnd-driver.c) int init_module(void) { int result; result=register_chrdev(IOM_FND_MAJOR,IOM_FND_NAME,&iom_fnd_fops); if(result<0) return result; fnd_major=IOM_FND_MAJOR; iom_fnd_addr=ioremap(IOM_FND_ADDRESS,0x02); return 0; } void cleanup_module(void) if(WaitQ_count == 0){ WaitQ_count++; interruptible_sleep_on(&WaitQ_fnd); iounmap(iom_fnd_addr); unregister_chrdev(fnd_major,IOM_FND_NAME)
open/release (fnd-driver.c) int iom_fnd_open(struct inode *minode, struct file *mfile) { if(fnd_usage != 0) return -EBUSY; MOD_INC_USE_COUNT; fnd_usage = 1; return 0; } int iom_fnd_release(struct inode *minode, struct file *mfile) MOD_DEC_USE_COUNT; fnd_usage = 0;
write (fnd-driver.c) ssize_t iom_fnd_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what) { const char *tmp = gdata; unsigned char value,cathode = 0xff; int i; unsigned char fnd_buff[5]; copy_from_user(fnd_buff, tmp, length); // 3 bytes received for(i=0; i<6; i++){ if(i%2) value=Getsegcode((fnd_buff[i/2]>>4)&0xf); else value=Getsegcode(fnd_buff[i/2]&0xf); value_digit[i]=(unsigned short)((value<<8)|(cathode&~(0x1<<(5-i)))); } queue_task(&Task, &tq_timer); // put in the task queue return length;
Getsegcode (fnd-driver.c) char Getsegcode(int x) { char code; switch (x) { case 0x0 : code = 0x3f; break; case 0x1 : code = 0x06; break; case 0x2 : code = 0x5b; break; case 0x3 : code = 0x4f; break; case 0x4 : code = 0x66; break; case 0x5 : code = 0x6d; break; case 0x6 : code = 0x7d; break; case 0x7 : code = 0x07; break; case 0x8 : code = 0x7f; break; case 0x9 : code = 0x6f; break; case 0xA : code = 0x77; break; case 0xB : code = 0x7c; break; case 0xC : code = 0x39; break; case 0xD : code = 0x5e; break; case 0xE : code = 0x79; break; case 0xF : code = 0x71; break; default : code = 0; break; } return code;
display (fnd-driver.c) void iom_fnd_display(void* value) { int i; unsigned short* tmp; tmp =(unsigned short* )value; for(i=0; i<6; i++){ outw(tmp[i],iom_fnd_addr); // fnd output udelay(1000); } if(WaitQ_count){ wake_up_interruptible(&WaitQ_fnd); outw(0x3f,iom_fnd_addr); // fnd turn off } else queue_task(&Task, &tq_timer); // task_queue에 다시 넣음
FND 응용 프로그램 (fnd-app.c) int main(int argc, char **argv) { int dev; unsigned buff; if((dev=open("/dev/fnds",O_WRONLY))==-1){ fprintf(stderr,"can not open /dev/fnds\n"); exit(1); } buff=(unsigned)strtol(&argv[1][0],NULL,16); write(dev,&buff,3); close(dev); return(0);
Makefile all: fnd-driver fnd-app fnd-driver: arm-linux-gcc -Wall -D KERNEL_-DMODULE \ -I/home/et1/lab-03/linux-2.4.19-pxa255_pro2/include \ -c fnd-driver.c fnd-app: arm-linux-gcc fnd-app.c -o fnd-app clean: rm -f *.o fnd-app
FND 디바이스 드라이버 시험 호스트에서 디바이스 드라이버 프로그램 fnd-driver.c 및 응용 프로그램 fnd-app.c를 컴파일 만들어진 디바이스 드라이버 fnd-driver.o 및 응용 프로그램 fnd-app를 테스트 장비로 download 아래 절차에 따라 시험: # mknod /dev/fnds c 241 0 # insmod ./fnd-driver.o # ./fnd-app 123456 # ./fnd-app 654321 ... # rmmod fnd-driver