Chap 7

Similar documents
untitled

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

Microsoft PowerPoint - lab14.pptx

교육지원 IT시스템 선진화

Microsoft PowerPoint - lab15.pptx

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

KEY 디바이스 드라이버

ECE30076 Embedded System Programming - LED Device Driver

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

Microsoft Word doc

슬라이드 1

<4D F736F F F696E74202D20B8B6C0CCC5A9B7CEC7C1B7CEBCBCBCAD202839C1D6C2F7207E203135C1D6C2F >

Microsoft Word doc

PowerPoint 프레젠테이션

Chapter #01 Subject

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

교육지원 IT시스템 선진화

Microsoft PowerPoint - chap02-C프로그램시작하기.pptx

슬라이드 1

PowerPoint 프레젠테이션

임베디드시스템설계강의자료 6 system call 2/2 (2014 년도 1 학기 ) 김영진 아주대학교전자공학과

vi 사용법

<4D F736F F F696E74202D20B8B6C0CCC5A9B7CEC7C1B7CEBCBCBCAD202834C1D6C2F7207E2038C1D6C2F729>

제1장 Unix란 무엇인가?

본 강의에 들어가기 전

Microsoft PowerPoint - [2009] 02.pptx

Microsoft PowerPoint - es-arduino-lecture-03

< E20C6DFBFFEBEEE20C0DBBCBAC0BB20C0A7C7D12043BEF0BEEE20492E707074>

<4D F736F F F696E74202D20B8AEB4AABDBA20BFC0B7F920C3B3B8AEC7CFB1E22E BC8A3C8AF20B8F0B5E55D>

비트와바이트 비트와바이트 비트 (Bit) : 2진수값하나 (0 또는 1) 를저장할수있는최소메모리공간 1비트 2비트 3비트... n비트 2^1 = 2개 2^2 = 4개 2^3 = 8개... 2^n 개 1 바이트는 8 비트 2 2

커알못의 커널 탐방기 이 세상의 모든 커알못을 위해서

제1장 Unix란 무엇인가?

API 매뉴얼

슬라이드 1

/chroot/lib/ /chroot/etc/

Microsoft PowerPoint - chap13-입출력라이브러리.pptx

슬라이드 1

Adding a New Dev file

K&R2 Reference Manual 번역본

BMP 파일 처리

금오공대 컴퓨터공학전공 강의자료

11장 포인터

금오공대 컴퓨터공학전공 강의자료

<4D F736F F F696E74202D20BBB7BBB7C7D15F FBEDFB0A3B1B3C0B05FC1A638C0CFC2F72E BC8A3C8AF20B8F0B5E55D>

중간고사

Microsoft PowerPoint - IOControl [호환 모드]

Microsoft PowerPoint - ch07 - 포인터 pm0415

OCW_C언어 기초

<4D F736F F F696E74202D205BBAB0C3B75D20B8AEB4AABDBA20B5F0B9D9C0CCBDBA20B5E5B6F3C0CCB9F620B8F0B5A82E >

Microsoft PowerPoint - chap10-함수의활용.pptx

Microsoft Word - MPC850 SPI Driver.doc

Embeddedsystem(8).PDF

PowerPoint 프레젠테이션

제12장 파일 입출력

PowerPoint 프레젠테이션

1장. 유닉스 시스템 프로그래밍 개요

BY-FDP-4-70.hwp

<322EBCF8C8AF28BFACBDC0B9AEC1A6292E687770>

지난시간에... 우리는 kernel compile을위하여 cross compile 환경을구축했음. UBUNTU 12.04에서 arm-2009q3를사용하여 간단한 c source를빌드함. 한번은 intel CPU를위한 gcc로, 한번은 ARM CPU를위한 gcc로. AR

chap7.key

이번장에서학습할내용 동적메모리란? malloc() 와 calloc() 연결리스트 파일을이용하면보다많은데이터를유용하고지속적으로사용및관리할수있습니다. 2

UART Controller 구현

6주차.key

임베디드시스템설계강의자료 6 system call 1/2 (2014 년도 1 학기 ) 김영진 아주대학교전자공학과

목차 1. 키패드 (KeyPAD) 2. KeyPAD 를이용한비밀번호입력기

Microsoft PowerPoint - chap12-고급기능.pptx

// 변수선언 unsigned char i; unsigned char FONT[]={0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xD8, 0x80, 0x98}; //PORTA 를출력으로설정하고초기값은모두 0 PORTA = 0x00; DD

Microsoft PowerPoint - chap06-2pointer.ppt

디바이스드라이버 (Device Driver) Driver is literally a subject which drive a object. 응용프로그램에서하드웨어장치를이용해서데이터를직접읽고쓰거나제어해야하는경우에디바이스드라이버를이용 하드웨어를제어하는프로그램과애플리케이션에서

<B1E2BCFAB9AEBCAD5FB9DABAB4B1D45F F F64746F72732E687770>


ABC 11장

망고100 보드로 놀아보자 -13

RaspberryPi 커널컴파일및커널모듈 1 제 13 강 커널컴파일및커널모듈 커널컴파일가상주소 (mmap() 함수 ) 에의한디바이스제어커널모듈및커널모듈테스트커널모듈에의한입출력디바이스제어 (LED, BTN) 커널모듈을커널에포함하기

Sena Technologies, Inc. HelloDevice Super 1.1.0

강의10

API 매뉴얼

<4D F736F F F696E74202D20C1A63132B0AD20B5BFC0FB20B8DEB8F0B8AEC7D2B4E7>

Poison null byte Excuse the ads! We need some help to keep our site up. List 1 Conditions 2 Exploit plan 2.1 chunksize(p)!= prev_size (next_chunk(p) 3

IoT FND8 7-SEGMENT api

Microsoft PowerPoint - chap03-변수와데이터형.pptx

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

untitled

슬라이드 1

컴파일러

Microsoft PowerPoint - 10-EmbedSW-11-모듈

JAVA 프로그래밍실습 실습 1) 실습목표 - 메소드개념이해하기 - 매개변수이해하기 - 새메소드만들기 - Math 클래스의기존메소드이용하기 ( ) 문제 - 직사각형모양의땅이있다. 이땅의둘레, 면적과대각

Microsoft PowerPoint - 3ÀÏ°_º¯¼ö¿Í »ó¼ö.ppt

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

PowerPoint Presentation

Mango-IMX6Q mfgtool을 이용한 이미지 Write하기

2009년 상반기 사업계획

Transcription:

Chap 7 FPGA 디바이스

1. FPGA 디바이스 1.1. External FPGA Device Driver FPGA 모듈을제어하는디바이스드라이버를작성하는방법에대해서알아보도록한다. 이모듈은 Achro-i.MX6Q의 External Connector에연결된다. 본교재에는 FGPA 펌웨어소스코드가포함되어있지않지만 VHDL로작성할수있다. FGPA 관련소스는패키지에포함되어있는바이너리를이용하면된다. Achro-i.MX6Q 의 FPGA 확장모듈의중앙하단부에위치한 SW7 스위치 1 번을 ON( 상향 ) 해서사용자모드로설정한다. I/O 보드의 Mapping 정보는다음과같다. VHDL 코드는아래언급된디바이스를 사용할수있도록작성되어있으며, 아래 Address 에접근하여데이터를쓰거나, 읽 어서디바이스를제어할수있다. Demo Register 는소프트웨어로사용자모드 2

On/Off 를제어하기위해사용된다. 해당레지스터를 1(High) 로하면사용자모드로 설정된다. 번호 장치 어드레스 Node Major 1 LED 0x0800_0016 /dev/fpga_led 260 2 Seven Segment (FND) 0x0800_0004 /dev/fpga_fnd 261 3 Dot Matrix 0x0800_0210 /dev/fpga_dot 262 4 Text LCD 0x0800_0090 /dev/fpga_text_lcd 263 5 Buzzer 0x0800_0070 /dev/fpga_buzzer 264 6 Push Switch 0x0800_0050 /dev/fpga_push_switch 265 7 Dip Switch 0x0800_0000 /dev/fpga_dip_switch 266 8 Step Motor 0x0800_000C /dev/fpga_step_motor 267 EN Demo Register 0x0800_0300 N/A N/A 1.2. External LED Achro-i.MX6Q External Connector 에연결된 FPGA 의 LED 를제어하는디바이 스드라이버를개발한다. 1.2.1. 회로도분석 FGPA 보드에는 8 개의 LED 가연결되어있다. LED 회로도는아래의그림과동일 하다. 3

1.2.2. LED 제어예제소스 1 LED Device Driver 작성 (led_driver.c) LED1부터 8까지를제어할수있는디바이스드라이버소스를입력한다. /* FPGA LED Ioremap Control FILE : fpga_led_driver.c AUTH : largest@huins.com */ #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <asm/io.h> #include <asm/uaccess.h> #include <linux/kernel.h> #include <linux/ioport.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/version.h> 4

#define IOM_LED_MAJOR 260 #define IOM_LED_NAME "fpga_led" // ioboard led device major number // ioboard led device name #define IOM_LED_ADDRESS 0x08000016 // pysical address //Global variable static int ledport_usage = 0; static unsigned char *iom_fpga_led_addr; // define functions... ssize_t iom_led_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what); ssize_t iom_led_read(struct file *inode, char *gdata, size_t length, loff_t *off_what); int iom_led_open(struct inode *minode, struct file *mfile); int iom_led_release(struct inode *minode, struct file *mfile); // define file_operations structure struct file_operations iom_led_fops =.owner = THIS_MODULE,.open = iom_led_open,.write = iom_led_write,.read = iom_led_read,.release = iom_led_release, ; // when led device open,call this function int iom_led_open(struct inode *minode, struct file *mfile) if(ledport_usage!= 0) return -EBUSY; ledport_usage = 1; return 0; // when led device close,call this function int iom_led_release(struct inode *minode, struct file *mfile) ledport_usage = 0; return 0; // when write to led device,call this function ssize_t iom_led_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what) unsigned char value; unsigned short _s_value; const char *tmp = gdata; if (copy_from_user(&value, tmp, 1)) 5

return -EFAULT; _s_value = (unsigned short)value; outw(_s_value, (unsigned int)iom_fpga_led_addr); return length; // when read to led device,call this function ssize_t iom_led_read(struct file *inode, char *gdata, size_t length, loff_t *off_what) unsigned char value; unsigned short _s_value; char *tmp = gdata; _s_value = inw((unsigned int)iom_fpga_led_addr); value = _s_value & 0xF; if (copy_to_user(tmp, &value, 1)) return -EFAULT; return length; int init iom_led_init(void) int result; result = register_chrdev(iom_led_major, IOM_LED_NAME, &iom_led_fops); if(result < 0) printk(kern_warning"can't get any major\n"); return result; iom_fpga_led_addr = ioremap(iom_led_address, 0x1); printk("init module, %s major number : %d\n", IOM_LED_NAME, IOM_LED_MAJOR); return 0; void exit iom_led_exit(void) iounmap(iom_fpga_led_addr); unregister_chrdev(iom_led_major, IOM_LED_NAME); module_init(iom_led_init); module_exit(iom_led_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Huins"); 소스내용을살펴보면다음과같다. SROM Interface(I/F)n 통해 LED에접근하게된다. SROM I/F에서 FPGA와연결된주소는 0x0800_0000 이다. 이중 LED 연결을위해할당된주소는 0x0016 이다. 사용자모드로동작해야하고, DEMO_ADDRESS를직접제어할필요가있으므로, 이주소를참조할수있게설정 6

해둔다. 아래내용은장치이름을 fpga_led 로, Major 번호는 260 번으로설정하고 있다. #define IOM_LED_MAJOR 260 #define IOM_LED_NAME "fpga_led" // ioboard led device major number // ioboard led device name #define IOM_LED_ADDRESS 0x08000016 // pysical address 다음은디바이스를제어하는파일오퍼레이션스구조체 (fops) 이다. 구조체를살펴보면기존 gpio 소스와달리 read 함수를 write함수와함께기술하고있다. 일반적으로 gpio의경우는해당어드레스를읽거나쓰는한가지용도로설정하게되지만, fpga의경우는해당레지스터버퍼를읽고쓸수있는용도로설정할수있기때문이다. 따라서드라이버작성시에 write 함수와 read 함수를동시에기술했다. // define file_operations structure struct file_operations iom_led_fops =.owner = THIS_MODULE,.open = iom_led_open,.write = iom_led_write,.read = iom_led_read,.release = iom_led_release, ; 파일아래쪽에는디바이스초기화시에수행되는 init함수가구현되어있다. 이함수는드라이버가적재될때, 커널에해당드라이버를등록하고, 커널이사용해야할접근어드레스와데모어드레스에대해 ioreamp을시도한다. 이때, 맵핑되는크기는각각 1바이트 (8비트) 이다. FPGA에서는 8비트데이터만이용하기때문에 1바이트만맵핑하면된다. Demo Register의값을 ON(0x01,High) 로설정하여 FPGA를사용자모드로변경한다. 이제어플리케이션에서데이터를가져오거나가져다줄수있게된다. 7

int init iom_led_init(void) int result; result = register_chrdev(iom_led_major, IOM_LED_NAME, &iom_led_fops); if(result < 0) printk(kern_warning"can't get any major\n"); return result; iom_fpga_led_addr = ioremap(iom_led_address, 0x1); printk("init module, %s major number : %d\n", IOM_LED_NAME, IOM_LED_MAJOR); return 0; 2 LED Device 애플리케이션작성 (test_led.c) 아래소스코드는위에서작성한 led 디바이스드라이버를이용하여 LED를제어하는응용어플리케이션이다. /* FPGA LED Test Application File : fpga_test_led.c Auth : largest@huins.com */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define LED_DEVICE "/dev/fpga_led" int main(int argc, char **argv) int dev; unsigned char data; unsigned char retval; if(argc!=2) printf("please input the parameter! \n"); printf("ex)./test_led a1\n"); return -1; data = atoi(argv[1]); if((data<0) (data>8)) 8

exit(1); printf("invalid range!\n"); dev = open(led_device, O_RDWR); if (dev<0) printf("device open error : %s\n",led_device); exit(1); retval=write(dev,&data,1); if(retval<0) printf("write Error!\n"); return -1; sleep(1); data=0; retval=read(dev,&data,1); if(retval<0) printf("read Error!\n"); return -1; printf("current LED Value : %d\n",data); printf("\n"); close(dev); return(0); 애플리케이션내용은프로그램을실행할때인자를하나받도록한다. 인자는 0~8까지의숫자값만가능하고나머지는오류로처리한다. 오류가없으면장치를읽고쓰기가가능한형태로열고, 입력받은인자 (Argument) 값을해당장치에넣게된다. 9

dev = open(led_device, O_RDWR); if (dev<0) printf("device open error : %s\n",led_device); exit(1); retval=write(dev,&data,1); 값이정상적으로들어가게되면 LED 가점등한다. 1 이라는값은맨우측하단의 LED 를켜지게된다. LED 회로를보면 VDD가 LED에연결되었기때문에 LED의해당 IO가 Low(0) 이되면전류가흘러불이켜진다. FPGA에서는 Achro-i.MX6Q에서전달된값을 Invert 한다. 즉, Achro-i.MX6Q에서의 High(1) 값이해당회로에전달될때는 Low(0) 가되도록 FPGA가설계되어있다. 3 LED Device Driver Makefile 디바이스드라이버와응용프로그램을컴파일하기위해서 Makefile을만들어주자. #Makefile for a basic kernel module obj-m := fpga_led_driver.o KDIR :=/work/achroimx6q/achroimx_kernel // 커널위치는직접설치한위치로변경해야함! PWD :=$(shell pwd) all: driver app #all: driver driver: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules app: arm-none-linux-gnueabi-gcc -o fpga_test_led fpga_test_led.c install: cp -a fpga_led_driver.ko /nfsroot cp -a fpga_test_led /nfsroot clean: rm -rf *.ko rm -rf *.mod.* 10

rm -rf *.o rm -rf fpga_test_led rm -rf Module.symvers rm -rf modules.order rm -rf.led* 4 컴파일 Host PC에서 make 유틸리티를이용하여 2개의파일을컴파일한다. <Host PC> root@ubuntu:/work/achroimx6q# cp -a /media/achro-i.mx6q-1/dvd-1_s RC/examples/linux/f pga_driver/ /work/achroimx6q/ root@ubuntu:/work/achroimx6q# cd /work/achroimx6q/fpga_driver/ root@ubuntu:/work/achroimx6q/fpga_driver# tar xvf fpga_led.tar.gz root@ubuntu:/work/achroimx6q/fpga_driver# cd fpga_led root@ubuntu:/work/achroimx6q/fpga_driver/fpga_led# make 5 Achro-i.MX6Q 보드로복사하기위한준비 make 결과로생성된 led_driver.ko와 test_led 어플리케이션파일을 NFS를이용하여 Achro-i.MX6Q 보드로복사한다. Makefile은 make install시, /nfsroot로파일을복사하도록작성되어있다. 때문에 make install만입력하면 /nfsroot 디렉터리로파일복사가될것이다. <Host PC> root@ubuntu:/work/achroimx6q/fpga_driver/fpga_led# make install 6 Achro-i.MX6Q 보드로 Led driver 테스트프로그램복사 Achro-i.MX6Q의파일시스템으로해당드라이버와테스트프로그램을복사할수있다. nfs는네트워크가끊어지거나 mount가해제되면보드에서사용할수없다. 네트워크연결없이도보드에서바로실행하려면, 아래와같이마운트이후에해당파일들을파일시스템에복사하여남겨둔다. <Target board> [root@achro ~]# mount -t nfs 192.168.1.4:/nfsroot /mnt/nfs o rw,rsize=4096,nolock [root@achro ~]# cp -a /mnt/nfs/fpga_test_led /root [root@achro ~]# cp -a /mnt/nfs/fpga_led_driver.ko /root 11

7 디바이스드라이버와애플리케이션을실행먼저, insmod 명령으로디바이스드라이버를커널에올린다. 이어서, 디바이스와응용프로그램을묶어주는스페셜파일 ( 노드파일 ) 을만들어준다. mknod 명령을이용하여, 노드파일이름, 드라이버종류, 주번호, 부번호순으로입력한다. 끝으로, 응용프로그램인 test_app를실행시켜주자. <Target board> [root@achro ~]# insmod fpga_led_driver.ko [root@achro ~]# mknod /dev/fpga_led c 260 0 ( 파일이기존에있다는메시지가나오면무시하고다음을진행한다.) [root@achro ~]#./fgpa_test_led 1 1.2.3. LED 응용실행결과 실행결과는 "Current LED Value : 1" 이라는문자열과맨우측아래의 D8 LED 가켜지는것을확인할수있다. 1.3. FND 앞서 GPIO 를이용하여 LED 를점등하고소등하는디바이스드라이버를만들어보았 다. 이번에는 FPGA 의 FND 를제어하는디바이스드라이버를만들어보도록하자. FND(Flexible Number Display) 는 7-Segment 라고도하며, 숫자나영문자에대한 표현이가능한모듈이다. FND 는 2 가지형태의제품이일반적인데 Anode 와 Cathod 타입이그것이다. 자세한내용은해당제품의데이터시트를참고하기바란다. 12

1.3.1. FND 모듈 아래의그림은 FND 의구성형태와실제 FPGA 에부착된 4Digit FND 의모습이다. 1.3.2. 회로설명 Achro-i.MX6Q의확장보드에는 4Digit FND(Seven Segment) 가장착되어있다. LED와마찬가지로 FGPA의 Data Address에직접연결되어있다. Achro-i.MX6Q 에서 FND가맵핑된 Address는 0x08000004이다. 즉, 이어드레스에서부터장치가가지고있는데이터크기만큼메모리에기록을해주면 FND는그데이터에따라동작하게된다. 아래의데이터시트를보면 FND 모듈은 8개의데이터핀과 4개의디지트핀을가지고있다. 즉, 디바이스드라이버에서데이터핀과디지트핀을설정하고, 응용프로그램에서는디바이스드라이버에게데이터핀과디지트핀의정보를제공하면아래 FND의각디지트에서숫자가출력된다. 13

1.3.3. FND 디바이스드라이버예제앞서언급한것처럼, 아래디바이스드라이버예제는어드레스에연결된 FND를제어할수있다. 데이터를입력하는방법은 FND의해당비트 (a~dp 까지 ) 를 1로설정하면서숫자를만드는것이다. FPGA에부착된 4개의 Digit 각각은어드레스를가지게된다. 아래표는이를요약을한것이다. 디지트에숫자를표시하기하려면지정된어드레스에비트값을기록하여해당 FND가켜지게한다. Digit Address 1 / 2 0x0800_0004 3 / 4 0x0700_0006 Bit 7 6 5 4 3 2 1 0 FND D.P G F E D C B A 1 FND Device Driver 작성 (fnd_driver.c) FND도앞서 LED와동일한형태로구성된다. 차이점은표시할 digit가 4개이기때문에접근할수있는어드레스도 4개가된다는점이다. 실제드라이버소스에서는처음할당된어드레스영역으로부터 2Byte(16bit) 를할당받지만, 각각에대한어드레스를별도로할당받지않는다는것을확인할수있다. /* FPGA FND Ioremap Control FILE : fpga_fpga_driver.c AUTH : largest@huins.com */ #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <asm/io.h> #include <asm/uaccess.h> #include <linux/kernel.h> #include <linux/ioport.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/version.h> 14

#define IOM_FND_MAJOR 261 #define IOM_FND_NAME "fpga_fnd" // ioboard fpga device major number // ioboard fpga device name #define IOM_FND_ADDRESS 0x08000004 // pysical address //Global variable static int fpga_fnd_port_usage = 0; static unsigned char *iom_fpga_fnd_addr; // define functions... ssize_t iom_fpga_fnd_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what); ssize_t iom_fpga_fnd_read(struct file *inode, char *gdata, size_t length, loff_t *off_what); int iom_fpga_fnd_open(struct inode *minode, struct file *mfile); int iom_fpga_fnd_release(struct inode *minode, struct file *mfile); // define file_operations structure struct file_operations iom_fpga_fnd_fops =.owner = THIS_MODULE,.open = iom_fpga_fnd_open,.write = iom_fpga_fnd_write,.read = iom_fpga_fnd_read,.release = iom_fpga_fnd_release, ; // when fnd device open,call this function int iom_fpga_fnd_open(struct inode *minode, struct file *mfile) if(fpga_fnd_port_usage!= 0) return -EBUSY; fpga_fnd_port_usage = 1; return 0; // when fnd device close,call this function int iom_fpga_fnd_release(struct inode *minode, struct file *mfile) fpga_fnd_port_usage = 0; return 0; // when write to fnd device,call this function ssize_t iom_fpga_fnd_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what) 15

int i; unsigned char value[4]; unsigned short int value_short = 0; const char *tmp = gdata; if (copy_from_user(&value, tmp, 4)) return -EFAULT; value_short = value[0] << 12 value[1] << 8 value[2] << 4 value[3]; outw(value_short,(unsigned int)iom_fpga_fnd_addr); return length; // when read to fnd device,call this function ssize_t iom_fpga_fnd_read(struct file *inode, char *gdata, size_t length, loff_t *off_what) int i; unsigned char value[4]; unsigned short int value_short = 0; char *tmp = gdata; value_short = inw((unsigned int)iom_fpga_fnd_addr); value[0] =(value_short >> 12) & 0xF; value[1] =(value_short >> 8) & 0xF; value[2] =(value_short >> 4) & 0xF; value[3] = value_short & 0xF; if (copy_to_user(tmp, value, 4)) return -EFAULT; return length; int init iom_fpga_fnd_init(void) int result; result = register_chrdev(iom_fnd_major, IOM_FND_NAME, &iom_fpga_fnd_fops); if(result < 0) printk(kern_warning"can't get any major\n"); return result; iom_fpga_fnd_addr = ioremap(iom_fnd_address, 0x4); 16

printk("init module, %s major number : %d\n", IOM_FND_NAME, IOM_FND_MAJOR); return 0; void exit iom_fpga_fnd_exit(void) iounmap(iom_fpga_fnd_addr); unregister_chrdev(iom_fnd_major, IOM_FND_NAME); module_init(iom_fpga_fnd_init); module_exit(iom_fpga_fnd_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Huins"); 이예제도 LED 예제처럼 read와 write를할수있도록작성되어있다. LED 때와차이점은 read 혹은 write 시에 1바이트가 16비트를한번에 read/write한다. int init iom_fpga_fnd_init(void) int result; result = register_chrdev(iom_fnd_major, IOM_FND_NAME, &iom_fpg a_fnd_fops); if(result < 0) printk(kern_warning"can't get any major\n"); return result; iom_fpga_fnd_addr = ioremap(iom_fnd_address, 0x4); printk("init module, %s major number : %d\n", IOM_FND_NAME, IOM_FND_MAJOR); return 0; 데이터를기록할때는 unsigned char 배열 4 개를이용하여사용자공간으로부터 4 바이트데이터를받고, outw 함수를이용하여첫번째배열의값부터디바이스로 기록한다. 17

// when write to fnd device,call this function ssize_t iom_fpga_fnd_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what) int i; unsigned char value[4]; unsigned short int value_short = 0; const char *tmp = gdata; if (copy_from_user(&value, tmp, 4)) return -EFAULT; value_short = value[0] << 12 value[1] << 8 value[2] << 4 value[3]; outw(value_short,(unsigned int)iom_fpga_fnd_addr); return length; 2 FND Device Driver 작성 (test_fnd.c) 아래는 FND 디바이스드라이버를구동할수있는응용어플리케이션이다. /* FPGA FND Test Application File : fpga_test_fnd.c Auth : largest@huins.com */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #define MAX_DIGIT 4 #define FND_DEVICE "/dev/fpga_fnd" int main(int argc, char **argv) int dev; unsigned char data[4]; unsigned char retval; int i; int str_size; 18

memset(data,0,sizeof(data)); if(argc!=2) printf("please input the parameter! \n"); printf("ex)./test_led a1\n"); return -1; str_size=(strlen(argv[1])); if(str_size>max_digit) printf("warning! 4 Digit number only!\n"); str_size=max_digit; for(i=0;i<str_size;i++) if((argv[1][i]<0x30) (argv[1][i])>0x39) printf("error! Invalid Value!\n"); return -1; data[i]=argv[1][i]-0x30; dev = open(fnd_device, O_RDWR); if (dev<0) printf("device open error : %s\n",fnd_device); exit(1); retval=write(dev,&data,4); if(retval<0) printf("write Error!\n"); return -1; memset(data,0,sizeof(data)); sleep(1); retval=read(dev,&data,4); if(retval<0) printf("read Error!\n"); return -1; printf("current FND Value : "); 19

for(i=0;i<str_size;i++) printf("\n"); printf("%d",data[i]); close(dev); return(0); 테스트코드는입력받은인자 (Argument) 에숫자를제외한값이있는지확인한다. 없으면해당문자열의길이를확인한다. 길이가 1~4글자이하면해당데이터의크기만큼을디바이스에기록하는구조로작성되었다. dev = open(fnd_device, O_RDWR); if (dev<0) printf("device open error : %s\n",fnd_device); exit(1); retval=write(dev,&data,4); if(retval<0) printf("write Error!\n"); return -1; 3 Makefile 작성 #Makefile for a basic kernel module obj-m := fpga_fnd_driver.o KDIR PWD :=/work/achroimx6q/achroimx_kernel :=$(shell pwd) all: driver app #all: driver driver: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules app: arm-none-linux-gnueabi-gcc -o fpga_test_fnd fpga_test_fnd.c 20

install: clean: cp -a fpga_fnd_driver.ko /nfsroot cp -a fpga_test_fnd /nfsroot rm -rf *.ko rm -rf *.mod.* rm -rf *.o rm -rf fpga_test_fnd rm -rf Module.symvers rm -rf modules.order rm -rf.fnd* rm -rf.tmp* 1.3.4. FND 예제컴파일및실행 1 호스트시스템에서컴파일및 /nfsroot 디렉터리로복사 FND 소스디렉터리에서 make 명령으로컴파일한다음, make install을실행하여 /nfsroot로실행파일들을복사한다. <Host PC> root@ubuntu:/work/achroimx6q/fpga_driver# cd /work/achroimx6q/fpga_driver/ root@ubuntu:/work/achroimx6q/fpga_driver# tar xvf fpga_fnd.tar.gz root@ubuntu:/work/achroimx6q/fpga_driver# cd fpga_fnd root@ubuntu:/work/achroimx6q/fpga_driver/fpga_fnd# make root@ubuntu:/work/achroimx6q/fpga_driver/fpga_fnd# make install 2 Achro-i.MX6Q에서호스트의 nfsroot 디렉터리를마운트하고, 필요하면보드에서직접실행할수있도록드라이버와응용프로그램을복사할수있다. <Target Board> [root@achro ~]# mount -t nfs 192.168.1.4:/nfsroot /mnt/nfs -o rw,rsize=4096,nolock [root@achro ~]# cp -a /mnt/nfs/fpga_test_fnd /root [root@achro ~]# cp -a /mnt/nfs/fpga_fnd_driver.ko /root 1.3.5. 디바이스드라이버등록및프로그램실행 프로그램실행을위해서 fnd 드라이버를커널에적재한다음, 스페셜파일을만 들고, 테스트프로그램을구동시킨다. 21

<Target Board> [root@achro ~]# insmod fpga_fnd_driver.ko [root@achro ~]# mknod /dev/fpga_fnd c 261 0 ( 기존에존재한다고나오면무시하고, 다음라인을실행 ) [root@achro ~]#./fpga_test_fnd 1234 1.3.6. FND 응용실행결과 테스트프로그램이실행되면인수로입력한숫자가 FND 에출력되는것을확인할 수있다. 22

1.4. Dot Matrix 광고용으로많이사용되는소자로서지하철이나, 매장등, 우리주변에서흔히볼수있다. 도트매트릭스를광고를목적으로하는곳에많이사용하고있는이유는다른시스템보다가격이저렴하고사용하기가편하기때문이다. 일반적인도트매트릭스의구조는다음과같다. LED Array 구조로되어있다. 여기서사용하고있는 UD-D2388R은 Row Cathode 방식으로써 Row에 Low가입력되면 COL의입력상태에따라출력을나타낼수있다. 컴퓨터는한번 ( 한순간 ) 에한가지일밖에할수없다.(CPU가 1개인경우를말한다.) 동시에여러가지의일을하는듯이보이는것은속도가빠르기때문에그렇게보이는것이다. DOT-MATRIX의원리도이와비슷하게많은 LED를매우빠르게 ON/OFF하는것이다. 이번예제서부터컴파일하는방법과실행하는방법에 23

대해서는생략하도록하겠다. 디바이스드라이버컴파일방법은이전예시를따르 도록한다. 1.4.1. 회로설명 1 도트매트릭스회로아래는도트매트릭스와관련된회로도이다. 도트매트릭스에서원하는점을출력하기위해서는출력을원하는 ROW와 COL이각각 Low로설정되었을때, ROW 의값에따라해당도트가켜지게된다. Achro-i.MX6Q의 FPGA에서는 LED나 FND때와마찬가지로로직에서 invert 시키기때문에 Achro-i.MX6Q에서보내는데이터를 High로내보내야한다. 그러면 FPGA에서해당값을 Low로변경하여 LED에불이켜지도록한다. 2 어드레스맵과데이터기록포맷 FPGA 보드에서는각 ROW 를 8 비트로맵핑하고있다. 즉 7 비트를하나의 8 비트 24

어드레스로처리한다는의미이다. 즉 DOT 시작어드레스인 0x0800_0210부터 0x0800_0219까지각각라인별로맵핑한다고생각하면된다. 지금까지언급된부분을표로작성하면다음과같다. Address R7 R6 R5 R4 R3 R2 R1 R0 표현범위 0x0800_0210 0x0800_0211 0x0800_0212 0x0800_0213 0x0800_0214 0x0800_0215 0x0800_0216 0x0800_0217 0x0800_0218 0x0800_0219 0x00 ~ 0x7F 0x00 ~ 0x7F 0x00 ~ 0x7F 0x00 ~ 0x7F 0x00 ~ 0x7F 0x00 ~ 0x7F 0x00 ~ 0x7F 0x00 ~ 0x7F 0x00 ~ 0x7F 0x00 ~ 0x7F 위의표에서 R0~R7 부분이 7 비트로구성된부분이며 1 로설정하면 FND 에 LED 가켜지게된다. 위의표를이용하여 0~9 까지의정수를만들면다음과같다. 25

위의그림에서옆에표시된 16 진수가하나의열을표시하기위한값이다. 위의 값은드라이버테스트프로그램소스에서참조하는헤더파일 (fpga_dot_font.h) 로존 재한다. 1.4.2. DOT-MATRIX 디바이스드라이버및응용애플리케이션작성 1 dot matrix 폰트헤더 (fpga_dot_font.h) /* This file is FPGA-DOT MATRIX font file. FILE : fpga_dot_font.h AUTH : Hong, Sung-Hyun Huins, Inc. */ #ifndef FPGA_NUMBER #define FPGA_NUMBER unsigned char fpga_number[10][10] = 0x3e,0x7f,0x63,0x73,0x73,0x6f,0x67,0x63,0x7f,0x3e, // 0 0x0c,0x1c,0x1c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e, // 1 0x7e,0x7f,0x03,0x03,0x3f,0x7e,0x60,0x60,0x7f,0x7f, // 2 0xfe,0x7f,0x03,0x03,0x7f,0x7f,0x03,0x03,0x7f,0x7e, // 3 0x66,0x66,0x66,0x66,0x66,0x66,0x7f,0x7f,0x06,0x06, // 4 0x7f,0x7f,0x60,0x60,0x7e,0x7f,0x03,0x03,0x7f,0x7e, // 5 0x60,0x60,0x60,0x60,0x7e,0x7f,0x63,0x63,0x7f,0x3e, // 6 0x7f,0x7f,0x63,0x63,0x03,0x03,0x03,0x03,0x03,0x03, // 7 26

; 0x3e,0x7f,0x63,0x63,0x7f,0x7f,0x63,0x63,0x7f,0x3e, // 8 0x3e,0x7f,0x63,0x63,0x7f,0x3f,0x03,0x03,0x03,0x03 // 9 unsigned char fpga_set_full[10] = // memset(array,0x7e,sizeof(array)); 0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f ; unsigned char fpga_set_blank[10] = // memset(array,0x00,sizeof(array)); 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ; #endif 2 디바이스드라이버 (dot_driver.c) 도트매트릭스드라이버에서지금까지의드라이버와다소차이가나는부분은 FND처럼특정크기만큼한번에매핑을한다는점이다. /* FPGA Dot Matrix Ioremap Control FILE : fpga_dot_driver.c AUTH : largest@huins.com*/ #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <asm/io.h> #include <asm/uaccess.h> #include <linux/kernel.h> #include <linux/ioport.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/version.h> #include "./fpga_dot_font.h" 27

#define IOM_FPGA_DOT_MAJOR 262 #define IOM_FPGA_DOT_NAME "fpga_dot" // ioboard led device major number // ioboard led device name #define IOM_FPGA_DOT_ADDRESS 0x08000210 // pysical address //Global variable static int fpga_dot_port_usage = 0; static unsigned char *iom_fpga_dot_addr; // define functions... ssize_t iom_fpga_dot_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what); int iom_fpga_dot_open(struct inode *minode, struct file *mfile); int iom_fpga_dot_release(struct inode *minode, struct file *mfile); // define file_operations structure struct file_operations iom_fpga_dot_fops = owner: THIS_MODULE, open: iom_fpga_dot_open, write: iom_fpga_dot_write, release: iom_fpga_dot_release, ; // when fpga_dot device open,call this function int iom_fpga_dot_open(struct inode *minode, struct file *mfile) if(fpga_dot_port_usage!= 0) return -EBUSY; fpga_dot_port_usage = 1; return 0; // when fpga_dot device close,call this function int iom_fpga_dot_release(struct inode *minode, struct file *mfile) fpga_dot_port_usage = 0; return 0; // when write to fpga_dot device,call this function ssize_t iom_fpga_dot_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what) int i; unsigned char value[10]; unsigned short int _s_value; const char *tmp = gdata; if (copy_from_user(&value, tmp, length)) return -EFAULT; 28

for(i=0;i<length;i++) _s_value = value[i] & 0x7F; outw(_s_value,(unsigned int)iom_fpga_dot_addr+i*2); return length; int init iom_fpga_dot_init(void) int result; result = register_chrdev(iom_fpga_dot_major, IOM_FPGA_DOT_NAME, &iom_fpga_dot_fops); if(result < 0) printk(kern_warning"can't get any major\n"); return result; iom_fpga_dot_addr = ioremap(iom_fpga_dot_address, 0x10); printk("init module, %s major number : %d\n", IOM_FPGA_DOT_NAME, IOM_FPGA_DOT_MAJOR); return 0; void exit iom_fpga_dot_exit(void) iounmap(iom_fpga_dot_addr); unregister_chrdev(iom_fpga_dot_major, IOM_FPGA_DOT_NAME); module_init(iom_fpga_dot_init); module_exit(iom_fpga_dot_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Huins"); 앞서언급했던것처럼, FND 와동일한방식으로처리하지만 int 형으로 4Byte 단 위를표시했던것을지금은그보다범위가큰 10Byte 로매핑한다. 29

int init iom_fpga_dot_init(void) int result; result = register_chrdev(iom_fpga_dot_major, IOM_FPGA_DOT_NAME, &iom_fpga_dot_fops); if(result < 0) printk(kern_warning"can't get any major\n"); return result; iom_fpga_dot_addr = ioremap(iom_fpga_dot_address, 0x10); printk("init module, %s major number : %d\n", IOM_FPGA_DOT_NAME, \ IOM_FPGA_DOT_MAJOR); return 0; 2 응용프로그램 (test_dot.c) /* FPGA DotMatirx Test Application File : fpga_test_dot.c Auth : largest@huins.com */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include "./fpga_dot_font.h" #define FPGA_DOT_DEVICE "/dev/fpga_dot" int main(int argc, char **argv) int i; int dev; int str_size; int set_num; if(argc!=2) printf("please input the parameter! \n"); 30

printf("ex)./fpga_dot_test 7\n"); return -1; set_num = atoi(argv[1]); if(set_num<0 set_num>9) printf("invalid Numner (0~9)!\n"); return -1; dev = open(fpga_dot_device, O_WRONLY); if (dev<0) printf("device open error : %s\n",fpga_dot_device); exit(1); str_size=sizeof(fpga_number[set_num]); write(dev,fpga_number[set_num],str_size); close(dev); return 0; 3 Makefile #Makefile for a basic kernel module obj-m := fpga_dot_driver.o KDIR PWD APP :=/work/achroimx6q/achroimx_kernel :=$(shell pwd) := fpga_test_dot all: driver app #all: driver driver: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules app: arm-none-linux-gnueabi-gcc -o $(APP) $(APP).c 31

install: cp -a fpga_dot_driver.ko /nfsroot cp -a $(APP) /nfsroot clean: rm -rf *.ko rm -rf *.mod.* rm -rf *.o rm -rf $(APP) rm -rf Module.symvers rm -rf modules.order rm -rf.tmp* rm -rf.fpga* 1.4.3. DOT-Matrix 예제컴파일및실행 1 호스트시스템에서컴파일및 /nfsroot 디렉터리로복사 DOT-Matrix 소스디렉터리에서 make 명령을입력하여컴파일한다음, make install을실행하여 /nfsroot로실행파일들을복사해둔다. <Host PC> root@ubuntu:/work/achroimx6q/fpga_driver# cd /work/achroimx6q/fpga_driver/ root@ubuntu:/work/achroimx6q/fpga_driver# tar xvf fpga_dot.tar.gz root@ubuntu:/work/achroimx6q/fpga_driver# cd fpga_dot root@ubuntu:/work/achroimx6q/fpga_driver/fpga_dot# make root@ubuntu:/work/achroimx6q/fpga_driver/fpga_dot# make install 2 필요할경우, Achro-i.MX6Q 보드에서호스트의 /nfsroot 디렉터리를마운트하여, 드라이버와응용프로그램을복사해둔다. <Target Board> [root@achro ~]# mount -t nfs 192.168.1.4:/nfsroot /mnt/nfs -o rw,rsize=4096,nolock [root@achro ~]# cp -a /mnt/nfs/fpga_test_dot /root [root@achro ~]# cp -a /mnt/nfs/fpga_dot_driver.ko /root 1.4.4. 디바이스드라이버등록및프로그램실행 프로그램실행을위해먼저 dot 드라이버를커널에적재한다음, 스페셜파일을 만들어주고, 테스트프로그램을구동시킨다. 32

<Target Board> [root@achro ~]# insmod fpga_dot_driver.ko [root@achro ~]# mknod /dev/fpga_dot c 262 0 [root@achro ~]#./fpga_test_dot 7 1.4.5. DOT-Matrix 응용실행결과 fpga_test_dot 프로그램을실행할때인자로 7 을지정하였다. 1.5. Text LCD 제어하기 LCD 는액정디스플레이 (Liquid Crystal Display) 의약자로전자계산기나휴대폰등에많이사용되고있는디스플레이부품이다. 액정은전압이걸리면일정한방향으로늘어서는성질이있다. 이러한성질과전기신호에의한편광성질을이용하여전압이걸린곳을검게표시하게된다. LCD 는사용이편리하고전력소모가매우작아소규모휴대용컴퓨터시스템에서많이사용되며, 강력한기능을갖춘표시장치이다. LCD 는 LCD 패널과제어기가하나로되어있는모듈형태로구성된다. 제어기에서데이터버스를통하여데이터를전송하기만하면원하는표시를얻을수있다. FPGA 코드는이런 LCD 를제어할수있도록작성되어있다. 때문에 FPGA 가제공하는버퍼에데이터를쓰기만하면된다. 1.5.1. Text LCD 내부모듈구조 Text-LCD 모듈은 8bit 의 micro-processor 와 2 개의레지스터 (DR, IR) 로구성되 33

어있다. 기본적인사용방법은 IR 에명령어를설정하고, DR 에표시하고자하는데이터를쓰면된다. LCD Controller (HD44780) 에는 IR 과 DR 로사용되는 2 개의 8bit 레지스터가있 다. 이들은 LCD 모듈의 RS 입력신호에의해선택된다. 1 IR (Instruction Register) CPU 로부터받은데이터를써넣기만할수있다. LCD 화면클리어, 커서시프트, 글자 ON/OFF 등의 LCD 제어와관련된명령정보만을저장한다. 표시데이터 RAM(D.D.RAM) 과문자생성 RAM (C.G.RAM) 표시를위한 Address 정보를저장한다. 2 DR (Data Register) D.D.RAM 혹은 C.G.RAM 에써넣을데이터를저장하거나, D.D.RAM 혹은 C.G.RAM 으로부터읽어온데이터가일시적으로저장되는레지스터이다. CPU 로부터 DR 에써넣은데이터는 LCD 의내부동작으로 D.D.RAM 혹은 C.G.RAM 에자동으로써넣어진다. LCD 로부터데이터를읽기위해서어드레스정보를 IR 에써넣으면, DR 의내부동작에의해서 D.D.RAM 혹은 C.G.RAM 으로자동으로저장되고, DR 에저장된데이터가 CPU 로읽혀진다. 34

1.5.2. 회로도및맵핑된어드레스 IO보드에장착된문자 LCD의연결은다음과같다. 제어신호선인 EN, LE, RW, 그리고글자농도를결정하는 VO라인과 1,2번전원및 GND를제외하면 LCD DATA이다. 설정된어드레스는다음과같다. data 는 0x0800_0090~0x0800_00AF 까지즉, 32Byte 의데이터영역을가지게된다. 위문자 LCD 의경우 2x16(2 줄, 줄당 16 자 까지입력 ) 이므로, 1Byte*32 만큼의데이터공간이필요하다. 1.5.3. TEXT LCD 드라이버및응용프로그램 1 디바이스드라이버 (fpga_text_lcd_driver.c) /* FPGA TEXT_LCD Ioremap Control FILE : fpga_text_lcd_driver.c AUTH : largest@huins.com */ #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/slab.h> 35

#include <linux/platform_device.h> #include <linux/delay.h> #include <asm/io.h> #include <asm/uaccess.h> #include <linux/kernel.h> #include <linux/ioport.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/version.h> #define IOM_FPGA_TEXT_LCD_MAJOR 263 // ioboard led device major number #define IOM_FPGA_TEXT_LCD_NAME "fpga_text_lcd" // ioboard led device name #define IOM_FPGA_TEXT_LCD_ADDRESS 0x08000090 // pysical address - 32 Byte (16 * 2) //Global variable static int fpga_text_lcd_port_usage = 0; static unsigned char *iom_fpga_text_lcd_addr; // define functions... ssize_t iom_fpga_text_lcd_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what); int iom_fpga_text_lcd_open(struct inode *minode, struct file *mfile); int iom_fpga_text_lcd_release(struct inode *minode, struct file *mfile); // define file_operations structure struct file_operations iom_fpga_text_lcd_fops = owner: THIS_MODULE, open: iom_fpga_text_lcd_open, write: iom_fpga_text_lcd_write, release: iom_fpga_text_lcd_release, ; // when fpga_text_lcd device open,call this function int iom_fpga_text_lcd_open(struct inode *minode, struct file *mfile) if(fpga_text_lcd_port_usage!= 0) return -EBUSY; fpga_text_lcd_port_usage = 1; 36

return 0; // when fpga_text_lcd device close,call this function int iom_fpga_text_lcd_release(struct inode *minode, struct file *mfile) fpga_text_lcd_port_usage = 0; return 0; // when write to fpga_text_lcd device,call this function ssize_t iom_fpga_text_lcd_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what) int i; unsigned short int _s_value = 0; unsigned char value[32]; const char *tmp = gdata; if (copy_from_user(&value, tmp, length)) return -EFAULT; value[length]=0; printk("get Size : %d / String : %s\n",length,value); for(i=0;i<length;i++) _s_value = (value[i] & 0xFF) << 8 value[i + 1] & 0xFF; outw(_s_value,(unsigned int)iom_fpga_text_lcd_addr+i); i++; return length; int init iom_fpga_text_lcd_init(void) int result; result = register_chrdev(iom_fpga_text_lcd_major, IOM_FPGA_TEXT_LCD_NAME, &iom_fpga_text_lcd_fops); if(result < 0) printk(kern_warning"can't get any major\n"); return result; iom_fpga_text_lcd_addr = ioremap(iom_fpga_text_lcd_address, 0x32); 37

printk("init module, %s major number : %d\n", IOM_FPGA_TEXT_LCD_NAME, IOM_FPGA_TEXT_LCD_MAJOR); return 0; void exit iom_fpga_text_lcd_exit(void) iounmap(iom_fpga_text_lcd_addr); unregister_chrdev(iom_fpga_text_lcd_major, IOM_FPGA_TEXT_LCD_NAME); module_init(iom_fpga_text_lcd_init); module_exit(iom_fpga_text_lcd_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Huins"); 위소스코드를보면사용자공간에서문자열데이터를받아오고있음을알수있 다. 받아온데이터는문자열의길이만큼 LCD 의어드레스를 1 바이트씩증가시키며 기록한다. // when write to fpga_text_lcd device,call this function ssize_t iom_fpga_text_lcd_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what) int i; unsigned short int _s_value = 0; unsigned char value[33]; const char *tmp = gdata; if (copy_from_user(&value, tmp, length)) return -EFAULT; value[length]=0; for(i=0;i<length;i++) _s_value = (value[i] & 0xFF) << 8 value[i + 1] & 0xFF; outw(_s_value,(unsigned int)iom_fpga_text_lcd_addr+i); i++; return length; 38

맵핑은 32 바이트맵핑을한다. int init iom_fpga_text_lcd_init(void) int result; result = register_chrdev(iom_fpga_text_lcd_major, IOM_FPGA_TEXT_LCD_NAME, &iom_fpga_text_lcd_fops); if(result < 0) printk(kern_warning"can't get any major\n"); return result; iom_fpga_text_lcd_addr = ioremap(iom_fpga_text_lcd_address, 0x32); printk("init module, %s major number : %d\n", IOM_FPGA_TEXT_LCD_NAME, IOM_FPGA_TEXT_LCD_MAJOR); return 0; 2 응용애플리케이션 (test_textlcd.c) /* FPGA Text LCD Test Application File : fpga_test_text_lcd.c Auth : largest@huins.com */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define MAX_BUFF 32 #define LINE_BUFF 16 #define FPGA_TEXT_LCD_DEVICE "/dev/fpga_text_lcd" int main(int argc, char **argv) int i; int dev; int str_size; int chk_size; unsigned char string[32]; 39

memset(string,0,sizeof(string)); if(argc<2&&argc>3) printf("invalid Value Arguments!\n"); return -1; if(strlen(argv[1])>line_buff strlen(argv[2])>line_buff) printf("16 alphanumeric characters on a line!\n"); return -1; dev = open(fpga_text_lcd_device, O_WRONLY); if (dev<0) printf("device open error : %s\n",fpga_text_lcd_device); return -1; str_size=strlen(argv[1]); if(str_size>0) strncat(string,argv[1],str_size); memset(string+str_size,' ',LINE_BUFF-str_size); str_size=strlen(argv[2]); if(str_size>0) strncat(string,argv[2],str_size); memset(string+line_buff+str_size,' ',LINE_BUFF-str_size); write(dev,string,max_buff); close(dev); return(0); 위소스코드를보면 32 바이트의데이터를미리생성하고글자가들어가야할영역을추가한다. 나머지부분은공백처리를하고있다. 그내용은아래와같다. 40

str_size=strlen(argv[1]); if(str_size>0) strncat(string,argv[1],str_size); memset(string+str_size,' ',LINE_BUFF-str_size); str_size=strlen(argv[2]); if(str_size>0) strncat(string,argv[2],str_size); memset(string+line_buff+str_size,' ',LINE_BUFF-str_size); write(dev,string,max_buff); 3 Makefile 만들기 컴파일을위한 Makefile 을만든다. #Makefile for a basic kernel module obj-m := fpga_text_lcd_driver.o KDIR PWD APP :=/work/achroimx6q/achroimx_kernel :=$(shell pwd) := fpga_test_text_lcd all: driver app #all: driver driver: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules app: arm-none-linux-gnueabi-gcc -o $(APP) $(APP).c install: cp -a fpga_text_lcd_driver.ko /nfsroot cp -a $(APP) /nfsroot clean: rm -rf *.ko rm -rf *.mod.* rm -rf *.o rm -rf $(APP) rm -rf Module.symvers rm -rf modules.order rm -rf.tmp* rm -rf.fpga* 41

1.5.4. Text LCD 예제컴파일및실행 1 호스트시스템에서컴파일및 /nfsroot 디렉터리로복사 Text LCD 소스디렉터리에서 make 명령을입력해서컴파일한다음, make install을실행하여 /nfsroot로실행파일들을복사해둔다. <Host PC> root@ubuntu:/work/achroimx6q/fpga_driver# cd /work/achroimx6q/fpga_driver/ root@ubuntu:/work/achroimx6q/fpga_driver# tar xvf fpga_text_lcd.tar.gz root@ubuntu:/work/achroimx6q/fpga_driver# cd fpga_text_lcd root@ubuntu:/work/achroimx6q/fpga_driver/fpga_text_lcd# make root@ubuntu:/work/achroimx6q/fpga_driver/fpga_text_lcd# make install 2 필요할경우, Achro-i.MX6Q 보드에서바로실행할수있도록호스트의 /nfsroot 디렉터리를마운트하여드라이버와응용프로그램을복사해둔다.. <Target Board> [root@achro ~]# mount -t nfs 192.168.1.4:/nfsroot /mnt/nfs -o rw,rsize=4096,nolock [root@achro ~]# cp -a /mnt/nfs/fpga_test_text_lcd /root [root@achro ~]# cp -a /mnt/nfs/fpga_text_lcd_driver.ko /root 1.5.5. 디바이스드라이버등록및프로그램실행프로그램실행을위해먼저 lcd 드라이버를커널에적재한다음, 스페셜파일을만들고, 테스트프로그램을구동시킨다. <Target Board> [root@achro ~]# insmod fpga_text_lcd_driver.ko [root@achro ~]# mknod /dev/fpga_text_lcd c 263 0 [root@achro ~]#./fpga_test_text_lcd hello world < 실행예시 >./fpga test_text_lcd 1 3 ( 입력값을두개주어야함 ) 42

1.5.6. TextLCD 실행결과 TextLCD 실행결과는다음과같다. 애플리케이션실행시입력한값은 hello와 world이다. 첫번째인자인 hello는윗줄에출력되고, 두번째인자인 world는아래쪽에출력된다. 1.6. DIP Switch 지금까지 I/O 보드의레지스터에값을기록하여동작시키는예제만작성했다. 이 번실습에서는반대로, 현재상태값을가져와서출력해주는예제를작성해본다. 1.6.1. 딥스위치회로도및맵핑어드레스 DIP 타입스위치를나타낸다. IC 형태의칩에서서로마주보는핀사이로스위치가일렬로배치되어있다. 보통컴퓨터또는주변기기의상태를표시하기위해사용된다. 참고로 DIP은 Dual In-line Package의약자로집적회로 (IC) 를고정하는패키지를말한다. ( 지내발처럼생겼다.) 긴사각패키지의양끝을따라세로방향두줄로나란히배열하는데, 보통핀배열간격은 2.54mm (0.1인치) 이다. 핀들이회로기판의구명에들어가고구리로된패턴과함께납땜이되어전기적으로연결된다. I/O보드에는 SMD Type의 Switch가실장되어있다.(SMD Type이면적이작다.) SMD는 Surface Mounted Device의약어로전자제품의제조방식을말한다. 부품을기판에끼워서뒷면에다납땜을하는방식이아니라부품을기판위에얹어놓고납땜을하는것을말한다. 43

1 회로도아래회로도를보면, DIP_DATA와딥스위치사이에 VDD 3.3v가인가되고있다. 즉, 딥스위치가연결되면, DIP_DATA핀아무런값이들어가지않게되므로, LOW (0) 이된다. 딥스위치가연결상태가되면 VDD3.3V는딥스위치를거쳐접지로흘러가버리기때문이다. DIP 스위치가비연결상태가되면접지와연결되지않기때문에 DIP_DATA 핀에는 HIGH(1) 의값이들어가게된다. 2 맵핑된주소값은다음과같다. 0x0800_0000 1.6.2. 디바이스드라이버및응용애플리케이션작성 1 디바이스드라이버작성 (fpga_dip_switch_driver.c) /* FPGA DIP SWITCH Ioremap Control FILE : fpga_dip_switch_driver.c AUTH : largest@huins.com*/ #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <asm/io.h> 44

#include <asm/uaccess.h> #include <linux/kernel.h> #include <linux/ioport.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/version.h> #define IOM_FPGA_DIP_SWITCH_MAJOR 266 // ioboard led device major number #define IOM_FPGA_DIP_SWITCH_NAME "fpga_dip_switch" // ioboard led device name #define IOM_FPGA_DIP_SWITCH_ADDRESS 0x08000000 // pysical address //Global variable static int fpga_dip_switch_port_usage = 0; static unsigned char *iom_fpga_dip_switch_addr; // define functions... ssize_t iom_fpga_dip_switch_read(struct file *inode, char *gdata, size_t length, loff_t *off_what); int iom_fpga_dip_switch_open(struct inode *minode, struct file *mfile); int iom_fpga_dip_switch_release(struct inode *minode, struct file *mfile); // define file_operations structure struct file_operations iom_fpga_dip_switch_fops = owner: THIS_MODULE, open: iom_fpga_dip_switch_open, read: iom_fpga_dip_switch_read, release: iom_fpga_dip_switch_release, ; // when fpga_dip_switch device open,call this function int iom_fpga_dip_switch_open(struct inode *minode, struct file *mfile) if(fpga_dip_switch_port_usage!= 0) return -EBUSY; fpga_dip_switch_port_usage = 1; return 0; // when fpga_dip_switch device close,call this function int iom_fpga_dip_switch_release(struct inode *minode, struct file *mfile) fpga_dip_switch_port_usage = 0; 45

return 0; // when read from fpga_dip_switch device,call this function ssize_t iom_fpga_dip_switch_read(struct file *inode, char *gdata, size_t length, loff_t *off_what) unsigned char dip_sw_value; unsigned short _s_dip_sw_value; _s_dip_sw_value = inw((unsigned int)iom_fpga_dip_switch_addr); dip_sw_value = _s_dip_sw_value & 0xFF; if (copy_to_user(gdata, &dip_sw_value, 1)) return -EFAULT; return length; int init iom_fpga_dip_switch_init(void) int result; result = register_chrdev(iom_fpga_dip_switch_major, IOM_FPGA_DIP_SWITCH_NAME, &iom_fpga_dip_switch_fops); if(result < 0) printk(kern_warning"can't get any major\n"); return result; iom_fpga_dip_switch_addr = ioremap(iom_fpga_dip_switch_address, 0x1); printk("init module, %s major number : %d\n", IOM_FPGA_DIP_SWITCH_NAME, IOM_FPGA_DIP_SWITCH_MAJOR); return 0; void exit iom_fpga_dip_switch_exit(void) iounmap(iom_fpga_dip_switch_addr); unregister_chrdev(iom_fpga_dip_switch_major, IOM_FPGA_DIP_SWITCH_NAME); module_init(iom_fpga_dip_switch_init); module_exit(iom_fpga_dip_switch_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Huins"); 46

기존에는값을쓰는명령이주를이뤘다면딥스위치는입력장치로서값을읽을수만있는장치이다. 그러므로드라이버에 write 함수가존재할필요가없다. 매핑된 8비트레지스터의값을사용자공간으로보내현재딥스위치의설정값을응용프로그램에서이용하는구조이다. 2 응용프로그램작성 (test_dip.c) /* FPGA DIP Switch Test Application File : fpga_test_dip.c Auth : largest@huins.com */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <signal.h> unsigned char quit = 0; void user_signal1(int sig) quit = 1; int main(void) int dev; unsigned char dip_sw_buff = 0; dev = open("/dev/fpga_dip_switch", O_RDWR); if (dev<0) printf("device Open Error\n"); close(dev); return 1; (void)signal(sigint, user_signal1); printf("press <ctrl+c> to quit. \n"); while(!quit) usleep(400000); read(dev, &dip_sw_buff, 1); printf("read dip switch: 0x%02X \n", dip_sw_buff); close(dev); 위테스트프로그램은사용자시그널을등록하고있다. 등록된시그널은 SIGINT 로서사용자가프로그램을종료하기위해 Ctrl+C 키를동시에누르면발생한다. 이때커널에등록된사용자인터럽트는 quit 변수를 1로변경하기때문에 47

while(false) 문을빠져나와프로그램이종료된다. 소스코드에서사용자시그널을 등록하는부분을확인할수있다. //...( 생략 ) unsigned char quit = 0; //...( 생략 ) void user_signal1(int sig) quit = 1; //...( 생략 ) (void)signal(sigint, user_signal1); 3 Makefile 작성 (Makefile) #Makefile for a basic kernel module obj-m := fpga_dip_switch_driver.o KDIR PWD :=/work/achroimx6q/achroimx_kernel :=$(shell pwd) all: driver app #all: driver driver: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules app: arm-none-linux-gnueabi-gcc -o fpga_test_dip_switch fpga_test_dip_switch.c install: cp -a fpga_dip_switch_driver.ko /nfsroot cp -a fpga_test_dip_switch /nfsroot clean: rm -rf *.ko rm -rf *.mod.* rm -rf *.o rm -rf fpga_test_dip_switch rm -rf Module.symvers rm -rf.tmp* rm -rf.fpga* rm -rf modules.order 1.6.3. Dip Switch 예제컴파일및실행 48

1 호스트시스템에서컴파일및 /nfsroot 디렉터리로복사 DIP Switch 소스디렉터리에서 make 명령을입력하여컴파일한다음, make install을실행하여 /nfsroot로실행파일들을복사해둔다. <Host PC> root@ubuntu:/work/achroimx6q/fpga_driver# cd /work/achroimx6q/fpga_driver/ root@ubuntu:/work/achroimx6q/fpga_driver# tar xvf fpga_dip_switch.tar.gz root@ubuntu:/work/achroimx6q/fpga_driver# cd fpga_dip_switch root@ubuntu:/work/achroimx6q/fpga_driver/fpga_dip_switch# make root@ubuntu:/work/achroimx6q/fpga_driver/fpga_dip_switch# make install 2 필요한경우, Achro-i.MX6Q 보드에서바로실행할수있도록호스트의 /nfsroot 디렉터리를마운트하여드라이버와응용프로그램을복사해둔다. <Target Board> [root@achro ~]# mount -t nfs 192.168.1.4:/nfsroot /mnt/nfs -o rw,rsize=4096,nolock [root@achro ~]# cp -a /mnt/nfs/fpga_test_dip_switch /root [root@achro ~]# cp -a /mnt/nfs/fpga_dip_switch_driver.ko /root 1.6.4. 디바이스드라이버등록및프로그램실행프로그램실행을위해먼저 dip_switch 드라이버를커널에적재한. 다음, 스페셜파일을만들어주고, 테스트프로그램을구동시킨다. <Target Board> [root@achro ~]# insmod fpga_dip_switch_driver.ko [root@achro ~]# mknod /dev/fpga_dip_switch c 266 0 [root@achro ~]#./fpga_test_dip_switch 1.6.5. Dip Switch 실행결과딥스위치 1,2,3,4를 ON 쪽으로맞춰둔다. 어플리케이션을실행하면다음과같이출력될것이다. 프로그램실행중에딥스위치위치를바꾸면해당값으로변경되는것을확인할수있다. 49

X root@ubuntu File Edit View Terminal Help root@achroimx6q nfs$ insmod fpga_dip_switch_driver.ko init module, fpga_dip_switch major number: 266 root@achroimx6q nfs$ mknod /dev/fpga_dip_switch c 266 0 root@achroimx6q nfs$./fpga_test_dip_switch Press <ctrl+c> to quit Read dip switch: 0xFF Read dip switch: 0xFF Read dip switch: 0xFF Read dip switch: 0xFF Read dip switch: 0xFF 1.7. Push Switch 앞서 DIP Switch에대한예제를진행했다. Dip Switch는가변이많지않은핀설정, 값의설정, 상태설정등과같은용도로이용되는게일반적이다. 반대로자주값이변경이되거나혹은즉시한번만사용하는경우에는 Push Switch가주로이용된다. 이번에는 Achro-i.MX6Q의 Push Switch를다뤄보도록한다. Push Switch 도외부의입력을받아오는장치로서 Read 관련동작만진행하게된 다. 1.7.1. Push Switch 회로도및맵핑어드레스 Achro-FPGA에는 9개의 Push Switch가부착되어있다. Push Switch에입력이발생하게되면 FPGA는그값을버퍼에담아두게된다. 담아둔값을 Achro-i.MX6Q의드라이버가읽어오게된다. Push Switch를누르고있는동안 1 의값을유지하게되고놓으면 0으로설정되도록구성되어있다. 1 회로도 50

2 맵핑된주소값은다음과같다. 0x0800_0050 1.7.2. 디바이스드라이버및응용애플리케이션작성 1 디바이스드라이버작성 (fpga_push_driver.c) /* FPGA PUSH SWITCH Ioremap Control FILE : fpga_push_switch_driver.c AUTH : largest@huins.com*/ #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <asm/io.h> #include <asm/uaccess.h> #include <linux/kernel.h> #include <linux/ioport.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/version.h> #define MAX_BUTTON 9 #define IOM_FPGA_PUSH_SWITCH_MAJOR 265 // ioboard led device major number #define IOM_FPGA_PUSH_SWITCH_NAME "fpga_push_switch" // ioboard led device name #define IOM_FPGA_PUSH_SWITCH_ADDRESS 0x08000050 // pysical address //Global variable 51

static int fpga_push_switch_port_usage = 0; static unsigned char *iom_fpga_push_switch_addr; static unsigned char *iom_demo_addr; // define functions... ssize_t iom_fpga_push_switch_read(struct file *inode, char *gdata, size_t length, loff_t *off_what); int iom_fpga_push_switch_open(struct inode *minode, struct file *mfile); int iom_fpga_push_switch_release(struct inode *minode, struct file *mfile); // define file_operations structure struct file_operations iom_fpga_push_switch_fops = owner: THIS_MODULE, open: iom_fpga_push_switch_open, read: iom_fpga_push_switch_read, release: iom_fpga_push_switch_release, ; // when fpga_push_switch device open,call this function int iom_fpga_push_switch_open(struct inode *minode, struct file *mfile) if(fpga_push_switch_port_usage!= 0) return -EBUSY; fpga_push_switch_port_usage = 1; return 0; // when fpga_push_switch device close,call this function int iom_fpga_push_switch_release(struct inode *minode, struct file *mfile) fpga_push_switch_port_usage = 0; return 0; // when read from fpga_push_switch device,call this function ssize_t iom_fpga_push_switch_read(struct file *inode, char *gdata, size_t length, loff_t *off_what) int i; unsigned char push_sw_value[max_button]; unsigned short int _s_value = 0x00; for(i=0;i<=length;i++) _s_value = inw((unsigned int)iom_fpga_push_switch_addr+i*2); 52

push_sw_value[i] = _s_value &0xFF; if (copy_to_user(gdata, push_sw_value, length)) return -EFAULT; return length; int init iom_fpga_push_switch_init(void) int result; result = register_chrdev(iom_fpga_push_switch_major, IOM_FPGA_PUSH_SWITCH _NAME, &iom_fpga_push_switch_fops); if(result < 0) printk(kern_warning"can't get any major\n"); return result; iom_fpga_push_switch_addr = ioremap(iom_fpga_push_switch_address, 0x18); printk("init module, %s major number : %d\n", IOM_FPGA_PUSH_SWITCH_NAME, IOM_FPGA_PUSH_SWITCH_MAJOR); return 0; void exit iom_fpga_push_switch_exit(void) iounmap(iom_fpga_push_switch_addr); u n r e g i s t e r _ c h r d e v ( I O M _ F P G A _ P U S H _ S W I T C H _ M A J O R, IOM_FPGA_PUSH_SWITCH_NAME); module_init(iom_fpga_push_switch_init); module_exit(iom_fpga_push_switch_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Huins"); 위소스코드의중요한내용은 Button 각각이버퍼를가지고있기때문에, 각버 53

튼의값을가져오기위해서 9 개버튼의버퍼데이터를반복문을통해가져온다음 사용자공간으로그값을전달하는부분이다. // when read from fpga_push_switch device,call this function ssize_t iom_fpga_push_switch_read(struct file *inode, char *gdata, size_t length, loff_t *off_what) int i; unsigned char push_sw_value[max_button]; unsigned short int _s_value; for(i=0;i<=length;i++) _s_value = inw((unsigned int)iom_fpga_push_switch_addr+i*2); push_sw_value[i] = _s_value &0xFF; if (copy_to_user(gdata, push_sw_value, length)) return length; return -EFAULT; 2 응용프로그램작성 (fpga_test_push.c) /* FPGA Push Switch Test Application File : fpga_test_push.c Auth : largest@huins.com */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <signal.h> #define MAX_BUTTON 9 unsigned char quit = 0; void user_signal1(int sig) quit = 1; int main(void) 54

int i; int dev; int buff_size; unsigned char push_sw_buff[max_button]; dev = open("/dev/fpga_push_switch", O_RDWR); if (dev<0) printf("device Open Error\n"); close(dev); return -1; (void)signal(sigint, user_signal1); buff_size=sizeof(push_sw_buff); printf("press <ctrl+c> to quit. \n"); while(!quit) usleep(400000); read(dev, &push_sw_buff, buff_size); for(i=0;i<max_button;i++) printf("[%d] ",push_sw_buff[i]); printf("\n"); close(dev); 3 Makefile #Makefile for a basic kernel module obj-m := fpga_push_switch_driver.o KDIR PWD :=/work/achroimx6q/achroimx_kernel :=$(shell pwd) all: driver app #all: driver driver: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules 55

app: arm-none-linux-gnueabi-gcc -o fpga_test_push_switch fpga_test_push_switch.c install: cp -a fpga_push_switch_driver.ko /nfsroot cp -a fpga_test_push_switch /nfsroot clean: rm -rf *.ko rm -rf *.mod.* rm -rf *.o rm -rf fpga_test_push_switch rm -rf Module.symvers rm -rf.tmp* rm -rf.fpga* rm -rf modules.order 1.7.3. Push Switch 예제컴파일및실행 1 호스트시스템에서컴파일및 /nfsroot 디렉터리로복사 Push Switch 소스디렉터리에서 make 명령을입력하여컴파일한다음, make install을실행하여 /nfsroot로실행파일들을복사해둔다. <Host PC> root@ubuntu:/work/achroimx6q/fpga_driver# cd /work/achroimx6q/fpga_driver/ root@ubuntu:/work/achroimx6q/fpga_driver# tar xvf fpga_push_switch.tar.gz root@ubuntu:/work/achroimx6q/fpga_driver# cd fpga_push_switch root@ubuntu:/work/achroimx6q/fpga_driver/fpga_dip_switch# make root@ubuntu:/work/achroimx6q/fpga_driver/fpga_dip_switch# make install 2 필요할경우, Achro-i.MX6Q 보드에서바로실행할수있도록호스트의 /nfsroot 디렉터리를마운트하여, 드라이버와응용프로그램을복사해둔다. <Target Board> [root@achro ~]# mount -t nfs 192.168.1.4:/nfsroot /mnt/nfs -o rw,rsize=4096,nolock [root@achro ~]# cp -a /mnt/nfs/fpga_test_push_switch /root [root@achro ~]# cp -a /mnt/nfs/fpga_push_switch_driver.ko /root 1.7.4. 디바이스드라이버등록및프로그램실행프로그램실행을위해먼저 push_switch 드라이버를커널에적재한다. 다음은스페셜파일을만들어주고, 테스트프로그램을구동시킨다. <Target Board> 56

[root@achro ~]# insmod fpga_push_switch_driver.ko [root@achro ~]# mknod /dev/fpga_push_switch c 265 0 [root@achro ~]#./fpga_test_push_switch 1.7.5. Push Switch 실행결과 프로그램이실행되면아홉개의숫자가출력된다. Push Switch 를누르면해당번 호에맞는값이 1 로출력이되는것을확인할수있다. X root@ubuntu File Edit View Terminal Help root@achroimx6q nfs$ insmod fpga_push_switch_driver.ko init module, fpga_push_switch major number: 265 root@achroimx6q nfs$ mknod /dev/fpga_push_switch c 265 0 root@achroimx6q nfs$./fpga_test_push_switch Press <ctrl+c> to quit [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] [0] 57

1.8. Buzzer 부저는피에조효과를통해서소리를출력한다. 피에조효과는힘을가해변형을주면표면에전압이발생하고반대로전압을걸면소자가이동하거나힘이발생하는현상을말한다. 기계적효과와전기적효과의상호변환효과를나타내는압전효과라고도말한다. 피에조현상을일으키는소자는움직이면서주파수 2만Hz이상의초음파를발생시키기때문에살균을위한초음파발생에도사용한다. 피에조모터나액추에이터를초음파모터, 초음파액추에이터라고도부르는것은이때문이다. 이러한압전부품들은전기음향변환기, 초음파가습기, 초음파진단장치등에응용된다. 최근에는같은크기의소형모터보다출력이높고소음이적어휴대폰카메라모 듈의줌 / 자동초점기능을위한렌즈구동장치로도개발되었다. 이외에도전자파가 없어다양한정보통신기기의부품으로활용될전망이다. 압전효과를내는소자로는수정이나전기석, 세라믹, 티탄산바륨등으로다양하며, 일반적인부저의종류는아래와같다. Circumference Fixing Method Nodal Mounting Method 1.8.1. Buzzer 회로도및맵핑어드레스 58

1 회로도 2 맵핑된어드레스 0x0800_0070 1.8.2. 디바이스드라이버및응용애플리케이션작성 1 디바이스드라이버 /* FPGA Buzzer Ioremap Control FILE : fpga_buzzer_driver.c AUTH : largest@huins.com */ #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <asm/io.h> #include <asm/uaccess.h> #include <linux/kernel.h> #include <linux/ioport.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/version.h> #define IOM_BUZZER_MAJOR 264 #define IOM_BUZZER_NAME "fpga_buzzer" // ioboard buzzer device major number // ioboard buzzer device name 59

#define IOM_BUZZER_ADDRESS 0x08000070 // pysical address //Global variable static int buzzer_port_usage = 0; static unsigned char *iom_fpga_buzzer_addr; static unsigned char *iom_demo_addr; // define functions... ssize_t iom_buzzer_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what); ssize_t iom_buzzer_read(struct file *inode, char *gdata, size_t length, loff_t *off_what); int iom_buzzer_open(struct inode *minode, struct file *mfile); int iom_buzzer_release(struct inode *minode, struct file *mfile); // define file_operations structure struct file_operations iom_buzzer_fops =.owner = THIS_MODULE,.open = iom_buzzer_open,.write = iom_buzzer_write,.read = iom_buzzer_read,.release = iom_buzzer_release, ; // when buzzer device open,call this function int iom_buzzer_open(struct inode *minode, struct file *mfile) if(buzzer_port_usage!= 0) return -EBUSY; buzzer_port_usage = 1; return 0; // when buzzer device close,call this function int iom_buzzer_release(struct inode *minode, struct file *mfile) buzzer_port_usage = 0; return 0; // when write to buzzer device,call this function ssize_t iom_buzzer_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what) unsigned char value; unsigned short int _s_value; const char *tmp = gdata; if (copy_from_user(&value, tmp, 1)) return -EFAULT; 60

_s_value = value & 0xF; outw(_s_value,(unsigned int)iom_fpga_buzzer_addr); return length; // when read to buzzer device,call this function ssize_t iom_buzzer_read(struct file *inode, char *gdata, size_t length, loff_t *off_what) unsigned char value; unsigned short int _s_value; char *tmp = gdata; _s_value = inw((unsigned int)iom_fpga_buzzer_addr); value = _s_value & 0xF; if (copy_to_user(tmp, &value, 1)) return -EFAULT; return length; int init iom_buzzer_init(void) int result; result = register_chrdev(iom_buzzer_major, IOM_BUZZER_NAME, &iom_buzzer_fops); if(result < 0) printk(kern_warning"can't get any major\n"); return result; iom_fpga_buzzer_addr = ioremap(iom_buzzer_address, 0x1); printk("init module, %s major number : %d\n", IOM_BUZZER_NAME, IOM_BUZZER_MAJOR); return 0; void exit iom_buzzer_exit(void) iounmap(iom_fpga_buzzer_addr); unregister_chrdev(iom_buzzer_major, IOM_BUZZER_NAME); 61

module_init(iom_buzzer_init); module_exit(iom_buzzer_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Huins"); 2 테스트프로그램 /* FPGA Buzzer Test Application File : fpga_test_buzzer.c Auth : largest@huins.com */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <signal.h> #define BUZZER_DEVICE "/dev/fpga_buzzer" unsigned char quit = 0; void user_signal1(int sig) quit = 1; int main(int argc, char **argv) int dev; unsigned char state=0; unsigned char retval; unsigned char data; dev = open(buzzer_device, O_RDWR); if (dev<0) printf("device open error : %s\n",buzzer_device); exit(1); (void)signal(sigint, user_signal1); 62