FPGA디바이스 제16강 FPGA 디바이스 제어 · 3Dot Matrix 0x210/dev/fpga_dot 262 4Text LCD...
Transcript of FPGA디바이스 제16강 FPGA 디바이스 제어 · 3Dot Matrix 0x210/dev/fpga_dot 262 4Text LCD...
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디바이스 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디바이스 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디바이스 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디바이스 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>