제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향)...

53
RaspberryPi FPGA디바이스 1 제16강 FPGA 디바이스 제어 ( Achro-EM Kit 활용 ) 카메라 모듈 테스트 동영상 스트리밍 FPGA 디바이스 제어(LED, BTN) Qt Creator에 의한 GUI 환경 GUI 환경에서의 디바이스 제어(LED)

Transcript of 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향)...

Page 1: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 1

제16강

FPGA 디바이스 제어( Achro-EM Kit 활용 )

카메라 모듈 테스트

동영상 스트리밍

FPGA 디바이스 제어(LED, BTN)

Qt Creator에 의한 GUI 환경

GUI 환경에서의 디바이스 제어(LED)

Page 2: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 2

시스템 전환

* 기존 라즈베리파이보드에서 SD 카드 뽑아,

Achro-EM kit에 삽입하고 전원 투입

Page 3: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 3

카메라 모듈

* 카메라 인터페이스 활성화

$ sudo raspi-config

* 기본 제공 명령

$ raspistill // 정지영상

$ raspivid // 동영상

Page 4: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 4

카메라 모듈(계속)

* 카메라 정지영상(jpg 포맷) 생성

: jpg 포맷으로 이미지 캡춰할 때

$ raspistill –v -o image.jpg // 5초 미리보기후

$ ls // image.jpg 파일 생성 확인

* 카메라 동영상(h264 포맷) 생성

: h264 포맷의 동영상을 5초동안 캡춰할 때

$ raspivid -o video.h264 -fps 30 -t 5000

-o : 출력파일이름, -fps : 초당프레임,

-t : 촬영시간(msec, 5000 = 5초)

$ ls // video.h264 파일 생성

Page 5: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 5

카메라 모듈(계속)

* 영상 파일 포맷 관련 패키지 설치

: 플레이어 및 포맷 변환 툴

$ sudo apt-get update

$ sudo apt-get upgrade

$ sudo apt-get install mplayer netcat ffmpeg gpac

Page 6: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 6

카메라 모듈(계속)

* 동영상 포맷 변환( h264 -> mkv )

: ffmpeg을 이용

$ ffmpeg –r 30 –i video.h264 –vcodec copy video.mkv

* 동영상 포맷 변환( h264 -> mp4 )

: MP4Box 사용

$ MP4Box –add video.h264 video.mp4

* 동영상 플레이어 ( mplayer )

$ mplayer –zoom –x 200 –y 200 video.mp4

Page 7: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 7

카메라 모듈(계속)

* 동영상 스트리밍 ( mjpg-streamer )

: 라즈베리파이 카메라모듈을 이용한 웹스트리밍 서비스

: 관련 라이브러리 및 cmake 패키지 설치

$ sudo apt-get update

$ sudo apt-get upgrade

$ sudo apt-get install git cmake libjpeg8-dev imagemagick -y

: videodev2.h 헤더파일 소프트 링크(생략 가능, 2019.1.29)

$ sudo ln -s /usr/include/linux/videodev2.h

/usr/include/linux/videodev.h

Page 8: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 8

카메라 모듈(계속)

: mjpg-streamer 소스 다운로드

$ cd ./IFC415/16_FPGA/camera

$ git clone https://github.com/liamfraser/mjpg-streamer

: mjpg-streamer 소스 컴파일

$ cd ./mjpg-streamer/mjpg-streamer-experimental

$ make clean

$ make

Page 9: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 9

카메라 모듈(계속)

: 스크립트를 작성하여 웹스트리밍 서비스 시작

$ pwd

/home/pi/IFC415/16_FPGA/camera

$ sudo nano mjpg.sh

export

STREAMER_PATH=$HOME/IFC415/16_FPGA/camera/mjpg-streamer/mjpg-streamer-experimental

export LD_LIBRARY_PATH=$STREAMER_PATH

$STREAMER_PATH/mjpg_streamer -i "input_raspicam.so -d 200" -o "output_http.so

-w $STREAMER_PATH/www"

주의) 마지막줄은 한 라인으로 작성(전체 3라인되게)

적색 경로를 각자 상황에 맞게 변경....

: 웹스트리밍 서비스 시작 ( 내정 포트 8080 )

$ sh mjpg.sh // 웹스트리밍을 위한 실행

Page 10: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 10

카메라 모듈(계속)

* 웹스트리밍 확인

: 웹브라우저의 주소창에서 http://192.168.0.40:8080/

: Javascript 메뉴 클릭

: 웹스트리밍 서비스 종료시 터미널 창에서 Ctrl-c 눌러 종료

Page 11: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 11

Page 12: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 12

FPGA 디바이스

* Achro-EM Kit

: 기본 하단의 SW7스위치 #1 OFF (하향) 설정시

각 디바이스를 독자 구동토록 설계 됨

: 실습시, 하단의 SW7스위치 #1을 ON(상향)하여

사용자 모드로 전환할 것

Page 13: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 13

FPGA 디바이스(계속)

* FPGA 디바이스의 어드레스 맵 ( 자체 주소체계 )

: 물리주소, 노드명, 주번호

순 장치 어드레스 Node Major

1 LED 0x016 /dev/fpga_led 260

2 Seven Segment (FND) 0x004 /dev/fpga_fnd 261

3 Dot Matrix 0x210 /dev/fpga_dot 262

4 Text LCD 0x090 /dev/fpga_text_lcd 263

5 Buzzer 0x070 /dev/fpga_buzzer 264

6 Push Switch 0x050 /dev/fpga_push_switch 265

7 Dip Switch 0x000 /dev/fpga_dip_switch 266

8 Step Motor 0x00C /dev/fpga_step_motor 267

EN Demo Register 0x300 N/A N/A

Page 14: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 14

FPGA 디바이스(계속)

* FPGA 디바이스 제어

: 제시된 소스는 커널 모듈로 구현

: 실행할 커널 버전의 커널 소스가 필요함

: linux-rpi-4.9.y에서 진행

$ ls /usr/src -l

total 12

lrwxrwxrwx 1 root root 18 Aug 1 11:51 linux -> ./linux-rpi-4.9.y/

drwxr-xr-x 24 pi pi 4096 Oct 22 2018 linux-rpi-4.13.34

drwxr-xr-x 25 pi pi 4096 Aug 2 12:17 linux-rpi-4.9.y

drwxr-xr-x 3 root root 4096 Nov 13 2018 sense-hat

: 컴파일시 Makefile에서 KDIR 환경변수에 소스 경로 지정

KDIR :=/usr/src/linux/

Page 15: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 15

FPGA 디바이스(계속)

* FPGA 인터페이스 모듈

: ./fpga_interface_driver/ 소스

: FPGA디바이스와 라즈베리파이 GPIO 핀간 매핑을 위한 모듈

: 각 디바이스 제어시 필히 미리 커널과 링크되어야 함

$ sudo insmod fpga_interface_driver.ko

$ cat fpga_interface_driver.c/* FPGA LED Ioremap ControlFILE : fpga_fpga_itf_driver.c*/

#include <linux/module.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/gpio.h>#include <asm-generic/bitsperlong.h>

#define CTRL_nWE 0#define CTRL_nOE 1

Page 16: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 16

#define CTRL_nCS 2

static struct gpio iom_fpga_address[] = { // A1 ~ A11, A0=LOW /*{ 10, GPIOF_OUT_INIT_LOW, "ADDRESS 00" },*/

{ 11, GPIOF_OUT_INIT_LOW, "ADDRESS 01" }, { 12, GPIOF_OUT_INIT_LOW, "ADDRESS 02" },

{ 13, GPIOF_OUT_INIT_LOW, "ADDRESS 03" }, { 14, GPIOF_OUT_INIT_LOW, "ADDRESS 04" },

{ 15, GPIOF_OUT_INIT_LOW, "ADDRESS 05" }, { 16, GPIOF_OUT_INIT_LOW, "ADDRESS 06" },

{ 17, GPIOF_OUT_INIT_LOW, "ADDRESS 07" }, { 18, GPIOF_OUT_INIT_LOW, "ADDRESS 08" },

{ 19, GPIOF_OUT_INIT_LOW, "ADDRESS 09" }, { 20, GPIOF_OUT_INIT_LOW, "ADDRESS 10" },

{ 21, GPIOF_OUT_INIT_LOW, "ADDRESS 11" },};

static struct gpio iom_fpga_data[] = { { 2, GPIOF_OUT_INIT_LOW, "DATA 0" },

{ 3, GPIOF_OUT_INIT_LOW, "DATA 1" }, { 4, GPIOF_OUT_INIT_LOW, "DATA 2" },

{ 5, GPIOF_OUT_INIT_LOW, "DATA 3" }, { 6, GPIOF_OUT_INIT_LOW, "DATA 4" },

{ 7, GPIOF_OUT_INIT_LOW, "DATA 5" }, { 8, GPIOF_OUT_INIT_LOW, "DATA 6" },

{ 9, GPIOF_OUT_INIT_LOW, "DATA 7" },};

Page 17: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 17

static struct gpio iom_fpga_control[] = { { 22, GPIOF_OUT_INIT_LOW, "nWE" }, { 23, GPIOF_OUT_INIT_LOW, "nOE" }, { 25, GPIOF_OUT_INIT_LOW, "nCS" },};

static void iom_fpga_itf_set_default(void) { int i = 0;

gpio_set_value(10, 0); // A0: always set to LOW

for (i=0; i<ARRAY_SIZE(iom_fpga_address); i++) { gpio_set_value(iom_fpga_address[i].gpio, 0); }

for (i=0; i<ARRAY_SIZE(iom_fpga_data); i++) { gpio_set_value(iom_fpga_data[i].gpio, 0); }

for (i=0; i<ARRAY_SIZE(iom_fpga_control); i++) { gpio_set_value(iom_fpga_control[i].gpio, 1); }}

static int iom_fpga_itf_open(void) { int ret = 0;

ret = gpio_request_array(iom_fpga_address,

Page 18: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 18

ARRAY_SIZE(iom_fpga_address)); if (ret) { printk(KERN_ERR "Unable to request address GPIOs: %d\n",

ret); return ret; }

ret = gpio_request_array(iom_fpga_data, ARRAY_SIZE(iom_fpga_data));

if (ret) { printk(KERN_ERR "Unable to request data GPIOs: %d\n", ret); return ret; }

ret = gpio_request_array(iom_fpga_control, ARRAY_SIZE(iom_fpga_control));

if (ret) { printk(KERN_ERR "Unable to request control GPIOs: %d\n",

ret); return ret; }

iom_fpga_itf_set_default(); return ret;}

static int iom_fpga_itf_release(void) { iom_fpga_itf_set_default();

Page 19: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 19

gpio_free_array(iom_fpga_address, ARRAY_SIZE(iom_fpga_address));

gpio_free_array(iom_fpga_data, ARRAY_SIZE(iom_fpga_data)); gpio_free_array(iom_fpga_control, ARRAY_SIZE(iom_fpga_control));

return 0;}

ssize_t iom_fpga_itf_write(unsigned int addr, unsigned char value) { size_t length = 1; int i = 0;

printk("FPGA WRITE: address = 0x%x, data = 0x%x \n", addr, value);

for (i=0; i<ARRAY_SIZE(iom_fpga_address); i++) { gpio_set_value(iom_fpga_address[i].gpio, (addr >> i) & 0x1); }

for (i=0; i<ARRAY_SIZE(iom_fpga_data); i++) { gpio_set_value(iom_fpga_data[i].gpio, (value >> i) & 0x1); }

gpio_set_value(iom_fpga_control[CTRL_nCS].gpio, 0); udelay(1); gpio_set_value(iom_fpga_control[CTRL_nWE].gpio, 0); udelay(5); //printk("CS:%d, ", gpio_get_value(iom_fpga_control[CTRL_nCS].gpio));

Page 20: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 20

//printk("WE:%d, ", gpio_get_value(iom_fpga_control[CTRL_nWE].gpio)); //printk("\n"); gpio_set_value(iom_fpga_control[CTRL_nWE].gpio, 1); gpio_set_value(iom_fpga_control[CTRL_nCS].gpio, 1);

/* // Debugging... for (i=0; i<ARRAY_SIZE(iom_fpga_address); i++) { printk("Address(%d):%d, ", i, gpio_get_value(iom_fpga_address[i].gpio)); }

printk("\n"); for (i=0; i<ARRAY_SIZE(iom_fpga_data); i++) { printk("Data(%d):%d, ", i, gpio_get_value(iom_fpga_data[i].gpio)); }

printk("\n"); printk("CS:%d, ", gpio_get_value(iom_fpga_control[CTRL_nCS].gpio)); printk("WE:%d, ", gpio_get_value(iom_fpga_control[CTRL_nWE].gpio)); printk("\n"); */

return length;

Page 21: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 21

}EXPORT_SYMBOL(iom_fpga_itf_write);

unsigned char iom_fpga_itf_read(unsigned int addr) { unsigned char value = 0; int i = 0;

for (i=0; i<ARRAY_SIZE(iom_fpga_address); i++) { gpio_set_value(iom_fpga_address[i].gpio, (addr >> i) & 0x1); }

gpio_set_value(iom_fpga_control[CTRL_nCS].gpio, 0); udelay(1); gpio_set_value(iom_fpga_control[CTRL_nOE].gpio, 0); udelay(1);

for (i=0; i<ARRAY_SIZE(iom_fpga_data); i++) { value += gpio_get_value(iom_fpga_data[i].gpio) << i; }

gpio_set_value(iom_fpga_control[CTRL_nCS].gpio, 1); gpio_set_value(iom_fpga_control[CTRL_nOE].gpio, 1);

printk("FPGA READ: address = 0x%x, data = 0x%x \n", addr, value);

return value;}EXPORT_SYMBOL(iom_fpga_itf_read);

Page 22: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 22

int __init iom_fpga_itf_init(void) { printk("init module: %s\n", __func__); iom_fpga_itf_open(); return 0;}

void __exit iom_fpga_itf_exit(void) { printk("exit module: %s\n", __func__); iom_fpga_itf_release();}

module_init(iom_fpga_itf_init);module_exit(iom_fpga_itf_exit);

MODULE_LICENSE("GPL");

$ cat Makefile#Makefile for a basic kernel module

obj-m := fpga_interface_driver.oKDIR :=/usr/src/linux/PWD :=$(shell pwd)..........

Page 23: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 23

: FPGA 인터페이스 모듈 컴파일

$ make

$ ls

Makefile fpga_interface_driver.ko .........

: 인터페이스 모듈 링크 (각 디바이스 제어에 앞서 필히 )

$ sudo insmod fpga_interface_driver.ko

Page 24: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 24

FPGA LED

* LED 디바이스 ( ./fpga_led/ )

: 회로도 (Low 신호 인가시 LED ON)

: 1바이트 데이터 (MSB..LED0..D1, ..., LSB..LED7..D8)

: 주의) Achro-EM(rPi)은 High신호 출력시 인버팅하도록 설계

Page 25: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 25

FPGA LED(계속)

: LED 디바이스 드라이버 소스

$ cat fpga_led_driver.c /* FPGA LED Ioremap ControlFILE : fpga_led_driver.c AUTH : [email protected] */

#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_LED_MAJOR 260 // ioboard led device major number#define IOM_LED_NAME "fpga_led" // ioboard led device name

Page 26: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 26

#define IOM_LED_ADDRESS 0x016 // pysical address

//Global variablestatic int ledport_usage = 0;

// 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 functionint 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

Page 27: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 27

int iom_led_release(struct inode *minode, struct file *mfile) {ledport_usage = 0;return 0;

}

// when write to led device ,call this functionssize_t iom_led_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what) {

unsigned char value;const char *tmp = gdata;if (copy_from_user(&value, tmp, 1))

return -EFAULT;

iom_fpga_itf_write((unsigned int)IOM_LED_ADDRESS,value);return length;

}

// when read to led device ,call this functionssize_t iom_led_read(struct file *inode, char *gdata, size_t length, loff_t *off_what) {

unsigned char value = 0;char *tmp = gdata;

value = iom_fpga_itf_read((unsigned int)IOM_LED_ADDRESS);if (copy_to_user(tmp, &value, 1))

return -EFAULT;return length;

}int __init iom_led_init(void) {

int result;

Page 28: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 28

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;

}printk("init module %s, major number %d, minor nuber %d\n",

IOM_LED_NAME, IOM_LED_MAJOR, result);return 0;

}

void __exit iom_led_exit(void) {unregister_chrdev(IOM_LED_MAJOR, IOM_LED_NAME);

}

module_init(iom_led_init);module_exit(iom_led_exit);

MODULE_LICENSE("GPL");MODULE_AUTHOR("Huins");

Page 29: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 29

FPGA LED(계속)

: LED 응용 프로그램 소스

- 1바이트 데이터를 정수형으로 명령행에서 입력

$ cat fpga_test_led.c /* FPGA LED Test ApplicationFile : fpga_test_led.c */

#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;int data;int retval;

if(argc!=2) {printf("please input the parameter! \n");

Page 30: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 30

printf("ex)./test_led 7 (0~255)\n");return -1;

}

data = atoi(argv[1]);if((data<0)||(data>0xff)) {

printf("Invalid range!\n"); exit(1); }

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; }

Page 31: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 31

printf("Current LED Value : %d\n",data);

printf("\n");

close(dev);

return(0);}

: Makefile

$ cat Makefile#Makefile for a basic kernel module

obj-m := fpga_led_driver.o

KDIR :=/usr/src/linux/

PWD :=$(shell pwd)

all: driver appdriver: $(MAKE) -C $(KDIR) SU

Page 32: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 32

FPGA LED(계속)

* 소스 컴파일 및 실행

: 컴파일 및 링크

$ cd fpga_led

$ make

// 필히 FPGA 인터페이스 모듈이 먼저 링크되어 있어야 함!!!!

$ sudo insmod fpga_led_driver.ko

$ sudo mknod /dev/fpga_led c 260 0

: 실행

$ sudo ./fgpa_test_led 1

Page 33: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 33

FPGA BTN

* Push switch 디바이스 ( ./fpga_push_switch/ )

: 회로도 (Press시 High 신호 출력)

: 9개 푸쉬버튼 스위치

Page 34: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 34

FPGA BTN(계속)

: BTN 모듈 소스

$ cat fpga_push_switch_driver.c/* FPGA PUSH SWITCH Ioremap ControlFILE : fpga_push_switch_driver.c AUTH : [email protected]*/

#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

Page 35: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 35

#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 0x050 // pysical address

extern unsigned char iom_fpga_itf_read(unsigned int addr);extern ssize_t iom_fpga_itf_write(unsigned int addr, unsigned char value);

//Global variablestatic 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,

};

Page 36: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 36

// when fpga_push_switch device open ,call this functionint 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 functionint 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 functionssize_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 char value;

for(i=0;i<=length;i++) {

value = iom_fpga_itf_read((unsigned int)IOM_FPGA_PUSH_SWITCH_ADDRESS+i); push_sw_value[i] = value &0xFF;

Page 37: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 37

}

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;

}

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) {

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);

Page 38: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 38

}

module_init(iom_fpga_push_switch_init);module_exit(iom_fpga_push_switch_exit);

MODULE_LICENSE("GPL");MODULE_AUTHOR("Huins");

: BTN 응용 프로그램 소스

$ cat fpga_test_push.c/* FPGA Push Switch Test ApplicationFile : fpga_test_push.cAuth : [email protected] */

#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

Page 39: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 39

unsigned char quit = 0;

void user_signal1(int sig) { quit = 1;}

int main(void) { 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);

Page 40: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 40

for(i=0;i<MAX_BUTTON;i++) { printf("[%d] ",push_sw_buff[i]); } printf("\n"); } close(dev);}

: Makefile

$ cat Makefile#Makefile for a basic kernel moduleobj-m := fpga_push_switch_driver.o

KDIR :=/usr/src/linux/PWD :=$(shell pwd)

..............

Page 41: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 41

FPGA BTN(계속)

* 소스 컴파일, 링크 및 실행

$ cd fpga_push_switch

$ make // 컴파일

$ sudo insmod fpga_push_switch_driver.ko // 링크

$ sudo mknod /dev/fpga_push_switch c 261 0 // 노드 생성

$ sudo ./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] [1] [0] [0] [0] [0][0] [0] [0] [0] [1] [0] [0] [0] [0][0] [0] [0] [0] [0] [0] [0] [0] [0][0] [0] [0] [1] [0] [1] [0] [0] [0][0] [0] [0] [1] [0] [1] [0] [0] [0][0] [0] [0] [1] [0] [1] [0] [0] [0][0] [0] [0] [0] [0] [0] [0] [0] [0][0] [0] [0] [0]................

Page 42: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 42

Page 43: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 43

Qt Creator 설치

* Qt Creator 설치

: Windows 프로그래밍과 흡사한 GUI 환경 제공

: 관련 패키지 설치

$ sudo apt-get update

$ sudo apt-get install build-essential

$ sudo apt-get install cmake

$ sudo apt-get install qtcreator

$ sudo apt-get install qt5-default

* 라즈베리보드 연결 툴 : mstsc 접속

: Kit의 디스플레이의 기본 해상도 낮음

Page 44: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 44

qt_test 프로젝트

* qt_test 프로젝트

: 단순한 창을 표시하는 프로그램

: 이 과정을 통해 관련 환경설정도 살펴봄

* Qt Creator 실행

: 시작-Programming 메뉴에 Qt Creator 아이콘 클릭

Page 45: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 45

: 새 프로젝트 항목 선택후, .....

Page 46: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 46

: 기본 포맷의 소스 자동 생성

: 자동 생성 파일들

$ pwd

/home/pi/IFC415/16_FPGA/gui

$ ls qt_test/

main.cpp mainwindow.h qt_test.pro

mainwindow.cpp mainwindow.ui qt_test.pro.user

Page 47: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 47

qt_test 프로젝트(계속)

* 환경설정

: 메뉴의 Tools – Options – Build& Run 선택

: 컴파일러 등등 설정, 각 탭에서의 경고표시 해결과정임

Page 48: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 48

: Compilers 탭에서

-Add – GCC - C을 선택, path항에 /usr/bin/gcc 입력

-Add – GCC - C++을 선택, path항에 /usr/bin/gcc입력

: Kits 탭에서

-compiler C: 항에 앞서 설정한 GCC 선택

-compiler C++: 항에 앞서 설정한 GCC 선택

: 설정이 완료되면 ( 경고 표시 없으면) OK 버튼 클릭하여 닫음

Page 49: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 49

qt_test 프로젝트(계속)

* qt_test 컴파일 및 실행

: 메뉴-Build 클릭 혹은 좌하단 삼각형 아이콘 클릭

: 컴파일후 실행하여 빈 창이 나타남

: 빌드 후의 결과 파일들

$ pwd/home/pi/IFC415/16_FPGA/gui$ ls build-qt_test-Desktop-Debug/main.o Makefile moc_mainwindow.o ....mainwindow.o moc_mainwindow.cpp qt_test

Page 50: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 50

qt_test 프로젝트(계속)

* 바탕화면에서 실행

: 실행 파일을 유저의 바탕화면으로 이동

$ cp build-qt_test-Desktop-Debug/qt_test ~/Desktop/

: ~/Desktop/ 확인

$ cd

$ ls ./Desktop/

pcmanfm.desktop qt_test

: 바탕화면의 gt_test 아이콘 더블클릭하여 실행

// 환경설정에서 실행디바이스를 Desktop 선택의 이유로

Page 51: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 51

GUI 통한 LED 제어

* FPGA LED 제어 ( ./gui/qt_fpga_led/ )

: Qt Creator 초기화면에서 Open Project 선택

: qt_fpga_led 프로젝트 개방하고, 빌드함

: 빌드 결과

$ pwd

/home/pi/IFC415/16_FPGA/gui

$ ls build-qt_fpga_led-Desktop-Debug/

main.o Makefile moc_mainwindow.o .....

mainwindow.o moc_mainwindow.cpp qt_fpga_led

: 실행파일을 바탕화면으로 복사 및 확인

$ cp build-qt_fpga_led-Desktop-Debug/qt_fpga_led ~/Desktop/

$ cd

$ ls ./Desktop/

pcmanfm.desktop qt_fpga_led

Page 52: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 52

GUI 통한 LED 제어(계속)

* 실행

: 바탕화면에 아이콘 생성

: 실행에 앞서 다음 모듈들이 링크되어 있어야 함

$ sudo insmod fpga_interface_driver.ko

$ sudo insmod fpga_led_driver.ko

$ sudo mknod /dev/fpga_led c 260 0

: 실행은 바탕화면의 해당 아이콘 더블 클릭

Page 53: 제16강 FPGA 디바이스 제어 - KOREATECH · : 기본 하단의 sw7스위치 #1 off (하향) 설정시 각 디바이스를 독자 구동토록 설계 됨: 실습시, 하단의

RaspberryPi FPGA디바이스 53

응용과제

[응용1] FPAG 디바이스 제어

: 기타의 FPGA 디바이스 동작 확인

: