64
RaspberryPi FPGA디바이스 1 제16강 FPGA 디바이스 제어 ( Achro-EM Kit 활용 ) FPGA 디바이스 제어(LED, BTN, ....) Qt Creator에 의한 GUI 환경 GUI 환경에서의 디바이스 제어(LED) 카메라 모듈 ( 동영상 스트리밍 ) 참고) 교재 제16장 QT Creator 설치해 올 것!!!( 본 자료 p.43 참조 )

FPGA디바이스 제16강 FPGA 디바이스 제어 · 3Dot Matrix 0x210/dev/fpga_dot 262 4Text LCD 0x090/dev/fpga_text_lcd263 5Buzzer 0x070/dev/fpga_buzzer264 6Push Switch 0x050/dev/fpga_push_switch265

  • Upload
    others

  • View
    10

  • Download
    0

Embed Size (px)

Citation preview

RaspberryPi FPGA디바이스 1

제16강

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

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

Qt Creator에 의한 GUI 환경

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

카메라 모듈 ( 동영상 스트리밍 )

참고) 교재 제16장

QT Creator 설치해 올 것!!!( 본 자료 p.43 참조 )

RaspberryPi FPGA디바이스 2

FPGA 디바이스

* 시스템 전환

: 기존 라즈베리파이보드에서 micro SD 카드 제거후,

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

: PuTTY 사용하여 192.168.0.40 접속하여 작업 진행

참고) 앞서의 커널 모듈 컴파일할 때의 환경이 필요함

: 커널 소스가 있는 버전의 커널이 실행중이어야 함

: 커널 소스 및 소스 홈디렉터리로의 심볼릭 링크

( /usr/src/linux 심볼릭 링크파일 )

RaspberryPi FPGA디바이스 3

FPGA 디바이스(계속)

* Achro-EM Kit ( 하단의 SW7 스위치 )

1) 디바이스 자체 테스트 모드 ( 디폴트 : 하향 )

ÞÞ : 각 디바이스의 동작을 자체 테스트 보이기

ÞÝ : 각 디바이스의 자체 테스트 숨김

2) 사용자 모드 ( 실습예제 실행할 때 )

ÝÝ : 하단의 SW7 #1을 상향으로 전환

RaspberryPi FPGA디바이스 4

FPGA 디바이스(계속)

* FPGA 디바이스의 어드레스(12bits) 맵

: PGA에 VHDL로 프로그래밍

: GPIO 핀을 활용하여 자체의 주소체계를 정의함

순 장치 어드레스 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

RaspberryPi FPGA디바이스 5

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/ // linux-rpi-4.9.y 심볼릭링크

RaspberryPi FPGA디바이스 6

FPGA 디바이스(계속)

* FPGA 인터페이스 모듈

: ./fpga_interface_driver/ 소스

: FPGA 디바이스와 타깃보드의 GPIO 핀간 매핑을 위한 모듈

: FPGA 디바이스 read, write 제어를 위한 함수 정의

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

: GPIO 핀의 용도 ( BCM_GPIO # 체계 )

- 주소(12bits) : #21(A11), ..., #10(A00)

- 데이터(8bits) : #9(D7), ..., #2(D0)

- 제어(3bits) : #25(nCS), #23(nOE), 22(nWE)

RaspberryPi FPGA디바이스 7

FPGA 디바이스(계속)

* FPGA 인터페이스 write, read 타이밍도(소스참조)

RaspberryPi FPGA디바이스 8

$ 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> // gpio관련 매크로 및 함수#include <asm-generic/bitsperlong.h>

#define CTRL_nWE 0 // iom_fpga_control[] 인덱스#define CTRL_nOE 1#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" },

RaspberryPi FPGA디바이스 9

{ 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" },};

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

RaspberryPi FPGA디바이스 10

}

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

RaspberryPi FPGA디바이스 11

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

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

// ㈜휴인스 매뉴얼 p.165 write 타이밍도 참조ssize_t iom_fpga_itf_write(unsigned int addr, unsigned char value) { size_t length = 1; int i = 0;

RaspberryPi FPGA디바이스 12

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

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

return length;}

EXPORT_SYMBOL(iom_fpga_itf_write);

// ㈜휴인스 매뉴얼 p.165 read 타이밍도 참조unsigned char iom_fpga_itf_read(unsigned int addr) { unsigned char value = 0;

RaspberryPi FPGA디바이스 13

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

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

RaspberryPi FPGA디바이스 14

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

RaspberryPi FPGA디바이스 15

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

$ make clean

$ make

$ ls

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

: FPGA 인터페이스 모듈을 커널에 링크

- 각 디바이스 제어에 앞서 필히 링크할 것!!

- 모듈 링크 전후로 gpio 핀 상태 확인

$ gpio readall // 링크 전 GPIO 상태

$ sudo insmod fpga_interface_driver.ko

$ gpio readall // 링크 후 GPIO 상태

RaspberryPi FPGA디바이스 16

FPGA LED

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

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

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

: 1바이트 데이터의 매핑관계 ( 데이터/회로/기판 )

( MSB/LED0/D1, ..., LSB/LED7/D8 )

RaspberryPi FPGA디바이스 17

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

RaspberryPi FPGA디바이스 18

#define IOM_LED_ADDRESS 0x016 // 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 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;

RaspberryPi FPGA디바이스 19

}

// when led device close ,call this functionint 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;

RaspberryPi FPGA디바이스 20

}

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;

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

RaspberryPi FPGA디바이스 21

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

RaspberryPi FPGA디바이스 22

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

RaspberryPi FPGA디바이스 23

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.........................

RaspberryPi FPGA디바이스 24

FPGA LED(계속)

* 소스 컴파일 및 실행

: 컴파일 및 링크

$ cd fpga_led

$ make

// 필히 fpga_interface_driver.ko 모듈이 먼저 링크되어 있어야 함!!!!

$ sudo insmod fpga_led_driver.ko

$ sudo mknod /dev/fpga_led c 260 0

: 실행 ( 명령행에서 데이터 전달 )

$ sudo ./fgpa_test_led 1

RaspberryPi FPGA디바이스 25

FPGA BTN

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

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

: 9개 푸쉬버튼 스위치

RaspberryPi FPGA디바이스 26

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

RaspberryPi FPGA디바이스 27

#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,

};

// when fpga_push_switch device open ,call this function

RaspberryPi FPGA디바이스 28

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

if (copy_to_user(gdata, push_sw_value, length))return -EFAULT;

return length;}

RaspberryPi FPGA디바이스 29

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) {unregister_chrdev(IOM_FPGA_PUSH_SWITCH_MAJOR,

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

RaspberryPi FPGA디바이스 30

: 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

unsigned char quit = 0;

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

int main(void) { int i; int dev; int buff_size;

RaspberryPi FPGA디바이스 31

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

RaspberryPi FPGA디바이스 32

: Makefile

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

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

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

RaspberryPi FPGA디바이스 33

FPGA BTN(계속)

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

$ cd fpga_push_switch

$ make // 컴파일

// 필히 fpga_interface_driver.ko 모듈이 먼저 링크되어 있어야 함!!!!

$ 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]................

RaspberryPi FPGA디바이스 34

* 기타의 디바이스 제어시

소스컴파일을 위해

Makefile의 편집이 필요함을 유의.......(2019년도)

RaspberryPi FPGA디바이스 35

Qt Creator 설치

* Qt Creator 설치

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

: GUI 라이브러리 제공, 컴파일러 및 디버거 없음

$ sudo apt-get update

$ sudo apt-get install build-essential

$ sudo apt-get install cmake

$ sudo apt-get install qtcreator // 13분 소요

$ sudo apt-get install qt5-default // 3분 소요

$ sudo find / -name qt5 // 설치 위치 확인

/usr/lib/arm-linux-gnueabihf/qt5/usr/share/qt5/usr/include/arm-linux-gnueabihf/qt5

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

: Achro-EM_Kit의 디스플레이 기본 해상도가 낮기때문에

RaspberryPi FPGA디바이스 36

qt_test 프로젝트

* qt_test 프로젝트

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

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

* Qt Creator 실행

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

RaspberryPi FPGA디바이스 37

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

- Application-Qt Widgets Application - Choose 클릭

RaspberryPi FPGA디바이스 38

- 프로젝트 이름 및 위치 설정 및

Use as default ...... 체크후 Next 클릭

RaspberryPi FPGA디바이스 39

- Kit Selection 창에서

Desktop 체크후 Next 클릭

RaspberryPi FPGA디바이스 40

- Class Information 화면에서, (필요에 따라 클래스이름 설정)

디폴트 내용 확인 후, Next 클릭

RaspberryPi FPGA디바이스 41

- 프로젝트관련 정보 확인후, Finish 클릭

RaspberryPi FPGA디바이스 42

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

: 자동 생성 파일들 ( 나중에 확인할 것 ! )

$ 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

RaspberryPi FPGA디바이스 43

qt_test 프로젝트(계속)

* 환경설정

: 메뉴의 Tools - Options 클릭한 후, Build & Run 선택

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

RaspberryPi FPGA디바이스 44

: Compilers 탭의 우상단 Add에서

- Add-GCC-C을 선택, path항에 /usr/bin/gcc 입력후, Apply 클릭

- Add-GCC-C++을 선택, path항에 /usr/bin/gcc입력후, Apply 클릭

: Kits 탭에서 ( !Desktop (default) 항 클릭 )

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

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

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

RaspberryPi FPGA디바이스 45

qt_test 프로젝트(계속)

* qt_test 컴파일 및 실행

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

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

: 빌드 후의 결과 파일들( ../build-프로젝트명-Desktop-Debug/ )

$ 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

RaspberryPi FPGA디바이스 46

qt_test 프로젝트(계속)

* 바탕화면에서 실행

: 실행 파일을 유저의 바탕화면(~/Desktop)으로 이동

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

: ~/Desktop/ 확인

$ cd

$ ls ./Desktop/

pcmanfm.desktop qt_test

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

// 환경설정에서 실행디바이스를 Desktop으로 선택하였기 때문

참고) Qt 프로그래밍을 위해서는 관련 책자 등을 참조

RaspberryPi FPGA디바이스 47

GUI 통한 LED 제어

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

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

: qt_fpga_led.pro 프로젝트 파일열고, 빌드함

: 빌드 결과

$ 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

RaspberryPi FPGA디바이스 48

GUI 통한 LED 제어(계속)

* 실행

: 바탕화면에 아이콘 생성

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

$ sudo insmod fpga_interface_driver.ko

$ sudo insmod fpga_led_driver.ko

$ sudo mknod /dev/fpga_led c 260 0

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

RaspberryPi FPGA디바이스 49

RaspberryPi FPGA디바이스 50

카메라 모듈

* 사전 확인 작업

: 업데이트 및 업그레이드한 최근 커널이 실행상태

: 즉, 실습진도상 커널 컴파일할때 퇴피한 커널 이미지를 복구

$ cd /boot

$ sudo mv kernel7.img kernel7_4.9.img // 현 커널이미지 퇴피

$ sudo mv kernel7_org.img kernel7.img // 원래 커널이미지로 복구

$ sudo reboot

$ uname -r

4.19.42-v7+ // 커널 컴파일전의 커널 버전 확인

$ ls /dev/vchiq -al // 카메라관련 디바이스 파일 존재여부

crw-rw---- 1 root video 243, 0 Dec 9 13:14 /dev/vchiq

RaspberryPi FPGA디바이스 51

카메라 모듈(계속)

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

: Interfacing options - camera 활성

$ sudo raspi-config

$ sudo reboot

* 기본 제공 명령 (이후 활용, ./cam_test에서 작업 )

: 정지영상 raspistill , 동영상 관련 명령 raspivid 제공

$ raspistill

RaspberryPi FPGA디바이스 52

카메라 모듈(계속)

참고) vchiq 관련 오류에 대한 조치

: 실습과정에서 커널이미지 변경 작업으로 인해 발생할 수 있음

( 퇴피하였던 커널이미지 버전으로 커널 변경하거나,

커널 업데이트 및 업그레이드 할 것!!)

$ raspistill

* failed to open vchiq instance

- /dev/vchiq 디바이스 드라이버 관련 오류임

$ ls -al /dev/vchiq // 해당 파일 존재 확인할 것!!!

참고) 존재함에도 오류발생시 조치

==> 접근권한 변경하거나, 로그인 계정을 video 그룹에 등록후 재부팅

$ sudo chmod 777 /dev/vchiq

혹은, $ sudo usermod -a -G video pi

$ sudo reboot

RaspberryPi FPGA디바이스 53

카메라 모듈(계속)

* 카메라 정지영상 생성

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

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

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

* 카메라 동영상 생성

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

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

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

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

$ ls // video.h264 파일 생성 확인

RaspberryPi FPGA디바이스 54

카메라 모듈(계속)

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

: 플레이어 및 포맷 변환 툴

$ sudo apt-get update

$ sudo apt-get upgrade

$ sudo apt-get install mplayer // mplayer 패키지

$ sudo apt-get install netcat ffmpeg gpac

// 패키지관리, ffmpeg, MP4Box 관련 패키지

RaspberryPi FPGA디바이스 55

카메라 모듈(계속)

* 동영상 포맷 변환( 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

RaspberryPi FPGA디바이스 56

카메라 모듈(계속)

* 동영상 스트리밍 ( ./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

RaspberryPi FPGA디바이스 57

카메라 모듈(계속)

참고) 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 // 컴파일

$ ls

CHANGELOG README-UNSTABLE mjpg_streamer output_file.so start.sh www

LICENSE TODO mjpg_streamer.c output_http.so utils.c

Makefile input_raspicam.so mjpg_streamer.h plugins utils.h

README input_uvc.so mjpg_streamer.o scripts utils.o

RaspberryPi FPGA디바이스 58

카메라 모듈(계속)

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

$ pwd

/home/pi/IFC415/16_FPGA/camera

$ 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 // 웹스트리밍을 위한 스크립트 파일 실행

RaspberryPi FPGA디바이스 59

카메라 모듈(계속)

* 웹스트리밍 확인

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

: Javascript 메뉴 클릭

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

RaspberryPi FPGA디바이스 60

카메라 모듈(계속)

[실습4] 웹스트리밍

: 웹서버 홈 디렉터리에서의 웹스트리밍 서비스

$ sudo cp javascript_simple.html /var/www/html

// mjpeg-streamer/.../www내 javascript_simple.html을

/var/www/html/로 복사

$ nano mjpg.sh // 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 /var/www/html"

$ sh mjpg.sh // 스크립트 실행

웹브라우저로 접속

( http://192.168.0.40:8080/javascript_simple.html )

RaspberryPi FPGA디바이스 61

참고) ./www/javascript_simple.html 소스

$ cat javascript_simple.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>MJPEG-Streamer</title></head>

<script type="text/javascript">

/* Copyright (C) 2007 Richard Atterer, richard�atterer.net This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2. See the file COPYING for details. */

var imageNr = 0; // Serial number of current imagevar finished = new Array();

// References to img objects which have finished downloadingvar paused = false;

function createImageLayer() { var img = new Image(); img.style.position = "absolute";

RaspberryPi FPGA디바이스 62

img.style.zIndex = -1; img.onload = imageOnload; img.onclick = imageOnclick; img.src = "/?action=snapshot&n=" + (++imageNr); var webcam = document.getElementById("webcam"); webcam.insertBefore(img, webcam.firstChild);}

// Two layers are always present, to avoid flickerfunction imageOnload() { this.style.zIndex = imageNr; // Image finished, bring to front! while (1 < finished.length) { var del = finished.shift(); // Delete old image(s) from document del.parentNode.removeChild(del); } finished.push(this); if (!paused) createImageLayer();}

// Clicking on the image will pause the streamfunction imageOnclick() { paused = !paused; if (!paused) createImageLayer();}

</script>

<body onload="createImageLayer();">

RaspberryPi FPGA디바이스 63

<div id="webcam"><noscript><img src="/?action=snapshot" /></noscript></div></body></html>

RaspberryPi FPGA디바이스 64

응용과제

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

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

: 제공된 소스 참조

[응용2] LED 제어 CGI + 웹스트리밍

: 기존 LED 원격 제어 상태를 웹스트리밍을 통해 눈으로

확인할 수 있도록 구현