Download presentation
Presentation is loading. Please wait.
1
11장 LDS2000 임베디드 실습
2
LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008에 위치
CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근
3
LED 접근 예제 [LDS2000-SW]/application/device/LED/led.c
int main() { int i, LED_fd; unsigned char *mmap_addr; unsigned char *LEDReg; LED_fd = open("/dev/mem", O_RDWR|O_SYNC); mmap_addr=mmap(NULL, , (PROT_READ|PROT_WRITE), MAP_SHARED, LED_fd, 0x ); /* CS2 */ LEDReg = (unsigned char *)(mmap_addr + 0x08); /* 0x */ for(i=0;i<8;i++) { *LEDReg = 0x01 << i ; sleep(1); } munmap(mmap_addr, 1024); close(LED_fd); return 0; } #include <sys/types.h> // for open #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> // for mmap #include <sys/mman.h> <가상 어드레스에 의한 LED제어 응용 프로그램>
4
KEYPAD Hardware KEYPAD IN, KEYPAD OUT 레지스터를 이용, KEYPAD 제어
데이터 D0 D1 D2로 3개의 열을 구분 A3,A1은 1, A2,A0는 0의 값을 가질 때, 즉 옵셋 0x0A 로 접근 KEYPAD OUT 레지스터 지정된 열에서 눌러진 4개의 키를 구분 A0,A1이 0, A2,A3이 1의 값을 가질 때, 즉 옵셋 0x0C로 접근 <KEYPAD의 하드웨어 흐름과 비트구성>
5
<모듈의 처리 함수 구조체 선언>
KEYPAD 모듈 선언 #include <linux/kernel.h> #include <linux/module.h> #ifdef CONFIG_MODVERSIONS #define MODVERSIONS #include <linux/modversions.h> #endif #include <linux/fs.h> #include <linux/kdev_t.h> #include <asm/uaccess.h> #include <linux/slab.h> #include <asm/io.h> #include <linux/ioport.h> #define DEVICE_NAME "KEYPAD" static int KEYPAD_Major = 0; static int KEYPAD_DeviceOpen = 0; unsigned char *KEYPAD_BasePtr; unsigned char *KEYPAD_IN_RegPtr; unsigned char *KEYPAD_OUT_RegPtr; int KEYPAD_virtual_memory_allocate(); void KEYPAD_virtual_memory_free(); static int KEYPAD_open(struct inode *inode,struct file *filp); static int KEYPAD_release(struct inode *inode,struct file *filp); static ssize_t KEYPAD_write(struct file *filp,const char *buffer,size_t length,loff_t *offset); static ssize_t KEYPAD_read(struct file *filp, char *buffer,size_t length,loff_t *offset); <헤더 파일 선언> struct file_operations KEYPAD_fops = { open : KEYPAD_open, release : KEYPAD_release, read : KEYPAD_read, write : KEYPAD_write, }; <모듈의 처리 함수 구조체 선언> <전역 변수/함수 선언>
6
KEYPAD init_module() & cleanup_module()
int init_module() { int error; KEYPAD_Major = register_chrdev(0, DEVICE_NAME, &KEYPAD_fops); printk("KEYPAD Device Driver registration OK with major number = %d\n",KEYPAD_Major); error = KEYPAD_virtual_memory_allocate(); return 0; } void cleanup_module() { int nRetCode; printk("Unloading KEYPAD Device Driver...\n"); KEYPAD_virtual_memory_free(); nRetCode = unregister_chrdev(KEYPAD_Major, DEVICE_NAME); int KEYPAD_virtual_memory_allocate() { KEYPAD_BasePtr = ioremap((unsigned int)0x , (unsigned int)(1024)); /* get virtual address for KEYPAD control register */ /* 0xA offset from base ptr, (0x A) */ KEYPAD_IN_RegPtr = KEYPAD_BasePtr + 0x0A; /* 0xC offset from base ptr, (0x C) */ KEYPAD_OUT_RegPtr = KEYPAD_BasePtr + 0x0C; return 0; } void KEYPAD_virtual_memory_free() { iounmap(KEYPAD_BasePtr); <모듈의 등록과 해제 함수> <keypad 제어 레지스터 접근을 위한 가상 주소 영역 설정과 해제>
7
KEYPAD open() & release()
int KEYPAD_open(struct inode *inode, struct file *filp) { printk("KEYPAD open with major/minor(%d / %d)\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); if (KEYPAD_DeviceOpen) { printk("KEYPAD Device Driver already open\n"); return -EBUSY; } ++KEYPAD_DeviceOpen; MOD_INC_USE_COUNT; return 0; } int KEYPAD_release(struct inode *inode, struct file *filp) { printk("KEYPAD release(close) with major/minor (%d / %d)\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); if (!KEYPAD_DeviceOpen) { printk("KEYPAD Device has not opened\n"); return -EINVAL; } --KEYPAD_DeviceOpen; MOD_DEC_USE_COUNT; return 0; } < 열기/닫기 처리 함수>
8
KEYPAD read() & write()
ssize_t KEYPAD_write(struct file *filp,const char *buffer, size_t length, loff_t *offset) { const char *data = buffer; int count=0; char c; while(length > 0) { get_user(c, (char *)(data++)); /* Get user data from kernel buffer (*buffer)*/ outb(c,KEYPAD_IN_RegPtr); /* write user data into KEYPAD IN register */ --length; ++count; } return count; } ssize_t KEYPAD_read(struct file *filp, char *buffer, size_t length, loff_t *offset) { unsigned char key[2]; int retval = 0; /* read KEYPAD OUT register, only lower 4 bit is used */ key[0] = *KEYPAD_OUT_RegPtr & 0x0F; key[1] = *KEYPAD_IN_RegPtr & 0x07; if(key[0] > 0x00 && key[0] < 0x10) retval = 1; put_user(key[0], buffer); put_user(key[1], buffer+1); return retval; } < 쓰기/읽기 처리 함수>
9
<KEYPAD 제어용 응용 프로그램>
#include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <math.h> #include <stdlib.h> char key_analyze(int column, char key); char key_map[3][4] = { {‘1’, ‘4’, ‘7’, ‘*’}, {‘2’, ‘5’, ‘8’, ‘0’}, {‘3’, ‘6’, ‘9’, ‘#’} }; int bi_int[8] = {0, 1, 2, 0, 3}; int main(int argc , char **argv) { int fd, i = 0; char data, key[2], key_pressed; fd = open("/dev/keypad", O_RDWR); while(1) { /* KEYPAD IN data */ data = 0x1 << i; write(fd, &data, 1); /* KEYPAD OUT check */ if(read(fd, key, 2)) { key_pressed = key_analyze(key[0], key[1]); printf("Key Pressed: %c\n", key_pressed); fflush(stdout); if (key_pressed == '#') { printf("Exit program \n"); break; } if (++i > 2) i = 0; close(fd); return 0; char key_analyze(const char key, const char column) { int idx, col; col = bi_int[column >> 1]; idx = bi_int[key >> 1]; return key_map[col][idx]; } <KEYPAD 제어용 응용 프로그램>
10
KEYPAD를 이용한 인터럽트 처리 KEYPAD의 인터럽트 발생
KEYPAD OUT 레지스터의 출력된 키 데이터를 OR 연산 연산 값과 KEYPAD IN 레지스터의 D3와 NAND 연산 후 CPU 인터럽트 입력 LDS2000에서는 KEYPAD의 인터럽트 선을 GP14에 연결 < 인터럽트 발생 조건> <KEYPAD의 인터럽트 흐름>
11
GPIO(General-Purpose I/O)
일반적인 용도로 사용 가능한 디지털 입출력 기능의 Port pin들임 PXA255의 GPIO는 총 85개이며 각각의 핀들은 입력 또는 출력으로 프로그램 될 수 있다. 핀이 입력으로 사용되면 인터럽트 소스의 기능도 수행이 가능하다. PXA255의 대부분의 GPIO는 단순히 디지털 입출력 뿐만 아니라 부가적인 기능을 갖고 있다. 부가적인 기능과 단순 IO는 함께 사용할 수 없기 때문에 하드웨어 설계시 유의해야 한다. <PXA255 Block Daigram>
12
GPIO와 인터럽트 인터럽트와 관련된 레지스터의 기능 인터럽트와 GPIO
GRER: 입력 핀의 상태가 Low에서 High로 변했을 때 GEDR을 1로 설정하는 것을 허가 GFER: 입력 핀의 상태가 High에서 Low로 변했을 때 GEDR을 1로 설정하는 것을 허가 GEDR: GRER이나 GFER의 허가 비트가 설정되어 있을 경우 해당 에지가 발생하면 1로 설정하여 에지 발생을 표시 인터럽트와 GPIO GPIO는 입력의 에지가 검출될 때 인터럽트가 발생하게 설정할 수 있다. 이것은 인터럽트 컨트롤러 안에 있는ICPR(Interrupt Controller Pending Register)를 설정함으로써 가능 GPIO 11-27: 개별적으로 인터럽트 발생의 허가와 불가를 선택할 수 없다. GPIO 0-10: 개별적으로 인터럽트 발생의 허가가 가능하다. <General-Purpose I/O Block Daigram>
13
인터럽트 처리 인터럽트 처리 Bottom half 방식 일반적으로 인터럽트에 등록된 핸들러 함수에서 처리
인터럽트 핸들러 함수는 태스크 호출 후 종료 실제적인 인터럽트 처리는 태스크 형태로 처리하도록 수행되는 기법 <bottom half 처리 흐름 >
14
KEYPAD 인터럽트 제어 모듈 헤더 파일과 함수 선언
#include <linux/kernel.h> /* We're doing kernel work */ #include <linux/module.h> /* Specifically, a module */ #include <asm/uaccess.h>/* for put_user */ #include <linux/init.h> #include <linux/fs.h> /* file operation */ #include <asm/io.h> #include <asm/irq.h> #include <linux/sched.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/ioport.h> #include <linux/interrupt.h> #include <asm/hardware.h> #ifdef CONFIG_MODVERSIONS #define MODVERSIONS #include <linux/modversions.h> #endif #define DEVICE_NAME "KEYPAD_INT" #define KEYPAD_MAJOR 88 #define KEYPAD_IRQ IRQ_GPIO(14) static int keypad_DeviceOpen = 0; static int keypad_IntNum = -1; unsigned char *Virtual_BasePtr, *KEYPAD_IN_RegPtr, *KEYPAD_OUT_RegPtr; int keypad_virtual_memory_allocate(); void keypad_virtual_memory_free(); void user_wait(unsigned int); static int Keypad_Open(struct inode *, struct file *); static int Keypad_Release(struct inode *, struct file *); static void keypad_handler(int irq, void *dev_id,struct pt_regs *regs); void keypad_BH_handler(void *); static void keypad_BH_bottom_handler();
15
전역 설정: 인터럽트 제어를 위한 구조체 모듈의 처리 함수 구조체 선언 큐 생성 및 태스크 등록
전역 설정: 인터럽트 제어를 위한 구조체 모듈의 처리 함수 구조체 선언 큐 생성 및 태스크 등록 /* 키 값을 알아내기 위한 코드는 인터럽트 처리 함수에 존재*/ static struct file_operations keypad_fops = { open: Keypad_Open, release: Keypad_Release, } /*태스크 큐를 생성하고 태스크 구조체 생성 */ DECLARE_TASK_QUEUE(keypad_TaskQ); /* Task Queue Declare */ struct tq_struct keypad_TaskQ_structure; /* Task Queue Structure */
16
Init_module() 인터럽트 함수 등록 #define KEYPAD_IRQ IRQ_GPIO(14)
Int init_module(void) { int keypad_Major; keypad_Major = register_chrdev(KEYPAD_MAJOR, DEVICE_NAME, &keypad_fops); keypad_virtual_memory_allocate(); /* Register IRQ14 interrupt number */ keypad_IntNum = KEYPAD_IRQ; request_irq(keypad_IntNum, keypad_irq_handler, SA_INTERRUPT, DEVICE_NAME, NULL); printk("Keypad IRQ(GP14) handler function registeration OK\n"); <플래그 설정 정보> <인터럽트 핸들러 등록함수>
17
Init_module() 인터럽트 처리 함수의 태스크 등록 bottom half 함수의 초기화 인터럽트 허용
/*routine 대응함수가 실제 인터럽트 처리 함수 */ keypad_TaskQ_structure.routine=keypad_BH_handler; keypad_TaskQ_structure.data = NULL; init_bh(KEYPAD_BH, keypad_BH_bottom_handler); /*태스크 초기화*/ *KEYPAD_IN_RegPtr = 0x0F; enable_irq(keypad_IntNum); /*내부 인터럽트 허용*/ return 0; }
18
IRQ_GPIO(14)의 분석 IRQ_GPIO(14)
/*include/asm-arm/arch/irqs.h*/ & /*include/asm/arch-pxa/irqs.h*/ #define IRQ_GPIO(x) \ (((x) < 2) ? (IRQ_GPIO0 + (x)) : GPIO_2_80_TO_IRQ(x)) ->#define IRQ_GPIO0 PXA_IRQ(8) /* GPIO0 Edge Detect */ #define PXA_IRQ(x) ((x) – PXA_IRQ_SKIP) #define PXA_IRQ_SKIP /* The first 8 IRQs asre reserved */ ->#define GPIO_2_80_TO_IRQ(i) ((i) - PXA_IRQ(32) + 2) IRQ_GPIO(14) == (((14) < 2) ? (IRQ_GPIO0 + 14) : GPIO_2_80_TO_IRQ(14) => GPIO_2_80_TO_IRQ(14) == 14 – PXA_IRQ(32) + 2 = 14 – (32 – PXA_IRQ_SKIP) + 2 = 14 – (32 – 8) + 2 = -8
19
cleanup_module() void cleanup_module (void) { int UnReg;
printk("Unloading KEYPAD Driver for interrupt\n"); if ( keypad_IntNum >= 0) { free_irq(keypad_IntNum, NULL); printk("IRQ(GP14) line is removed\n"); } else printk("IRQ2 line was not registered\n"); keypad_virtual_memory_free(); UnReg = unregister_chrdev(KEYPAD_MAJOR, DEVICE_NAME); printk("Unregistered with Major Number OK\n"); }
20
인터럽트 Handler 함수 & bottom half으로 처리되는 함수
/* interrupt handler for IRQ14 */ void keypad_irq_handler(int irq, void *dev_id,struct pt_regs *regs) { printk(" IRQ !!!!! \n"); /* block keypad interrupt */ *KEYPAD_IN_RegPtr=0x00; /* insert bottom half task into task queue */ queue_task(&keypad_TaskQ_structure, &keypad_TaskQ); /* call bottom half task */ mark_bh(KEYPAD_BH); } <인터럽트 핸들러 함수> /* 인터럽트에서 처리해야 할 실제 작업이 bottom half 방식으로 처리되는 것 */ void keypad_BH_bottom_handler() { /* run some task from task queue */ run_task_queue(&keypad_TaskQ); } <init_bh()에 의해 호출되었으며, mark_bh()가 호출될 때 실행되는 실제 함수>
21
Bottom Half 처리 함수 /* Bottom half function - detect which key is pressed */ void keypad_BH_handler(void *unused) { unsigned char buff; *KEYPAD_IN_RegPtr = 0x01; switch (*KEYPAD_OUT_RegPtr) { case 0x01 : buff='1'; printk("key = %c\n", buff); goto finish; case 0x02 : buff='4'; printk("key = %c\n", buff); goto finish; case 0x04 : buff='7'; printk("key = %c\n", buff); goto finish; case 0x08 : buff='*'; printk("key = %c\n", buff); goto finish; default : break; } *KEYPAD_IN_RegPtr = 0x02; case 0x01 : buff='2'; printk("key = %c\n", buff); goto finish; case 0x02 : buff='5'; printk("key = %c\n", buff); goto finish; case 0x04 : buff='8'; printk("key = %c\n", buff); goto finish; case 0x08 : buff='0'; printk("key = %c\n", buff); goto finish; *KEYPAD_IN_RegPtr = 0x04; case 0x01 : buff='3'; printk("key = %c\n", buff); goto finish; case 0x02 : buff='6'; printk("key = %c\n", buff); goto finish; case 0x04 : buff='9'; printk("key = %c\n", buff); goto finish; case 0x08 : buff='#'; printk("key = %c\n", buff); goto finish; finish: *KEYPAD_IN_RegPtr = 0x0F;
22
< 인터럽트 처리 응용 프로그램>
모듈의 인터럽트 처리에 의해 키 값을 읽어오고 있으므로 별도의 읽기, 쓰기가 불필요 < 인터럽트 처리 응용 프로그램> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <asm/fcntl.h> int main() { int fd; inti, j; if((fd = open("/dev/keypad_int", O_RDWR)) < 0) { perror("keypad device open fail\n"); exit(2); } printf("keypad Device Open!!\n"); printf("Checking interrupt signal from keypad \n"); close(fd); return 0; }
23
LED 와 KEYPAD 동시 제어 KEYPAD로부터 눌린 키를 받아 그에 해당하는 LED를 점등하는 응용 프로그램 작성
<응용 프로그램과 디바이스 드라이버의 처리 흐름>
24
연동 제어를 위한 모듈 #include <linux/kernel.h>
#include <linux/module.h> #ifdef CONFIG_MODVERSIONS #define MODVERSIONS #include <linux/modversions.h> #endif #include <linux/fs.h> #include <linux/kdev_t.h> #include <asm/uaccess.h> #include <linux/slab.h> #include <asm/io.h> #include <linux/ioport.h> #define DEVICE_NAME "KEYPAD_LED" static int KEYPAD_LED_Major = 0; static int KEYPAD_LED_DeviceOpen = 0; unsigned long *BR2_OR2; unsigned char *KEYPAD_BasePtr; unsigned char *LED_RegPtr; unsigned char *KEYPAD_IN_RegPtr; unsigned char *KEYPAD_OUT_RegPtr; int KEYPAD_LED_virtual_memory_allocate(); void KEYPAD_LED_virtual_memory_free(); static int KEYPAD_LED_open(struct inode *inode,struct file *filp); static int KEYPAD_LED_release(struct inode *inode,struct file *filp); static ssize_t KEYPAD_LED_write(struct file *filp,const char *buffer,size_t length,loff_t *offset); static ssize_t KEYPAD_LED_read(struct file *filp, char *buffer,size_t length,loff_t *offset); char key_analyze(char column, char key); void user_wait(unsigned int delay_factor); <헤더 파일과 함수 선언>
25
Init_module() for KEYPAD_LED
<모듈의 처리 함수 구조체 선언> struct file_operations KEYPAD_LED_fops = { open : KEYPAD_LED_open, release : KEYPAD_LED_release, read : KEYPAD_LED_read, write : KEYPAD_LED_write, }; <모듈의 등록과 해제 함수> int init_module(void) { KEYPAD_LED_Major = register_chrdev( 0, DEVICE_NAME, &KEYPAD_LED_fops); printk("KEYPAD_LED Device Driver registrered OK with major number = %d\n", KEYPAD_LED_Major); KEYPAD_LED_virtual_memory_allocate(); return 0; } void cleanup_module(void) { int nRetCode; printk("Unloading KEYPAD_LED Device Driver...\n"); KEYPAD_LED_virtual_memory_free(); nRetCode = unregister_chrdev(KEYPAD_LED_Major, DEVICE_NAME); int KEYPAD_LED_virtual_memory_allocate() { KEYPAD_BasePtr = ioremap((unsigned int)0x , (unsigned int)(1024)); /* 0 offset from base ptr, ( 0x ) */ LED_RegPtr = KEYPAD_BasePtr + 0x08; /* 0x0A offset from base ptr, ( 0x800000A ) */ KEYPAD_IN_RegPtr = KEYPAD_BasePtr + 0xA; /* 0x0C offset from base ptr, ( 0x800000C ) */ KEYPAD_OUT_RegPtr = KEYPAD_BasePtr + 0xC; return 0; } void KEYPAD_LED_virtual_memory_free() { iounmap(KEYPAD_BasePtr); <가상 주소 영역 설정과 해제>
26
KEYPAD_LED_open() & KEYPAD_LED_release()
int KEYPAD_LED_open(struct inode *inode, struct file *filp) { printk("KEYPAD_LED open with major/minor (%d / %d)\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); if (KEYPAD_LED_DeviceOpen) { printk("KEYPAD_LED Device Driver already open\n"); return -EBUSY; } ++KEYPAD_LED_DeviceOpen; MOD_INC_USE_COUNT; return 0; } <열기와 닫기 처리 함수> int KEYPAD_LED_release(struct inode *inode, struct file *filp) { printk("KEYPAD_LED release(close) with major/minor (%d / %d)\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); if (!KEYPAD_LED_DeviceOpen) { printk("KEYPAD_LED Device has not opened\n"); return -EINVAL; } --KEYPAD_LED_DeviceOpen; MOD_DEC_USE_COUNT; return 0; }
27
KEYPAD_LED_write() & KEYPAD_LED_read()
ssize_t KEYPAD_LED_write(struct file *filp,const char *buffer, size_t length, loff_t *offset) { const char *data; int count=0; char c; data = buffer; while(length > 0) { /* Get user data from kernel buffer */ get_user(c, (char *)(data++)); /* write user data into LED control register */ outb(c, LED_RegPtr); --length; ++count; } return count; } ssize_t KEYPAD_LED_read(struct file *filp, char *buffer, size_t length, loff_t *offset) { unsigned char key, key_num; int i; for (i=0;i<3;i++) { /* write sequencial scan data into KEYPAD IN register, 0x01, 0x02, 0x04 */ outb(0x1 << i, KEYPAD_IN_RegPtr); user_wait( ); /* read KEYPAD OUT register, only lower 4 bit is used*/ key = *KEYPAD_OUT_RegPtr & 0x0F; /* analyze which key os pressed */ key_num = key_analyze(i, key); /*check if any key is pressed, or skip to scan*/ if (key_num != 0) { put_user(key_num, (char *)buffer); key_num = '\0'; /* find valid key is pressed, so we return immediately */ return 1; } } /* end of for() */ /* no key is pressed */ put_user(0, (char *)buffer); return 1; } <쓰기/읽기 처리 함수소스>
28
연동 제어를 위한 응용 프로그램 #include <stdio.h> #include <fcntl.h>
#include <unistd.h> #include <stdlib.h> #include <math.h> int key_led_transform(char key); int main(int argc , char **argv) { int fd; int i, len; char data[2], key[2]; fd = open("/dev/keypad_led", O_RDWR|O_SYNC); while(1) { /* read which key is pressed */ len = read(fd, key, 1); /* detect any valid key */ if (key[0] != 0) { data[0] = key_led_transform(key[0]); switch(data[0]) { case -1: printf("Exit Program :: key=%c\n", key[0]); case 0x0F: printf("lower half LED ON :: key=%c\n", key[0]); break; case 0xF0: printf("upper half LED ON :: key=%c\n", default: printf("%c-th LED ON :: key=%c\n", key[0], key[0]); } /* turn on one LED according to key value */ write(fd, data, 1); } if (key[0] == '#') break; } close(fd); printf("KEYPAD_LED device driver close OK\n"); return 0; } <연동제어 응용 프로그램>
29
Key_lead_transform()
int key_led_transform(char key) { int retval; switch(key) { case '0': retval = 0x00; break; case '9': retval = 0x0F; break; case '*': retval = 0xF0; break; case '#': retval = -1; break; default : retval = 0x1 << (key – ‘1’); break; } return retval; } <연동제어 응용 프로그램(계속)>
30
LDS2000 확장 보드 활용 LDS2000 확장보드 <LDS2000 확장보드의 블록 다이어그램>
31
<확장보드 LED 제어 프로그램>
LDS2000 확장 LED 출력 제어 #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <asm/fcntl.h> int main() { int i, MemFD; unsigned char *mmap_addr; unsigned char *ExtBD_LEDReg; MemFD = open("/dev/mem", O_RDWR|O_SYNC); mmap_addr=mmap(NULL, 1024, (PROT_READ|PROT_WRITE), MAP_SHARED, MemFD, 0x ); /* CS5_Base + 0x */ ExtBD_LEDReg = (unsigned char *)(mmap_addr); /* LED TEST - 32bits access 상위 8비트 사용 */ for(i=0; i<8; ++i) { *ExtBD_LEDReg = 0x01 << i; sleep(1); } printf("\n Exit \n"); munmap(mmap_addr, 1024); close(MemFD); return 0; } <확장보드 LED 제어 프로그램>
32
<7-Segment 제어 레지스터의 비트 구성>
7-Segment LED 제어 5개의 7-segment 표현 값은 8비트 제어 레지스터에 의해 결정 상위 4비트:5개의 7-segment 구분 하위 4비트: 지정된 세그먼트 LED 십진 숫자 결정 <7-Segment 제어 레지스터의 비트 구성>
33
<7-Segment 제어 프로그램>
7-segment LED 출력 장치 제어 #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <asm/fcntl.h> int main() { int i, j, MemFD; unsigned char *mmap_addr; unsigned char *SevenSegReg; char *message[5] = { "First", "Second", "Third", "Fourth", "Fifth"}; printf("----- 7-Segment Test Program ----\n"); printf(" on the LDS2000 External Board \n\n"); MemFD = open("/dev/mem", O_RDWR|O_SYNC); mmap_addr=mmap(NULL, 1024, (PROT_READ|PROT_WRITE), MAP_SHARED, MemFD, 0x ); /* CS#5 Base + 0x80000 */ SevenSegReg = (unsigned char *)(mmap_addr); for (i = 0; i < 5; i++) { printf("------> %s Segment \n", message[i]); for (j = 0; j < 11; j++) { *SevenSegReg = i << 4 + j; sleep(1); } } printf("\n Exit \n"); munmap(mmap_addr, 1024); close(MemFD); return 0; <7-Segment 제어 프로그램>
34
LDS2000 확장 보드 제어(계속) USB 컨트롤러 드라이버 USB를 연결을 이용한 TCP/IP 연결 실습
LDS2000에서는 USB Server와 Client 지원 커널에서 제공하는 드라이버를 이용하여 USB 드라이버 실습
35
USB 컨트롤러 드라이버(계속) LDS2000의 커널 컴파일
[System type], [Intel PXA250/210 Implementations] 순서로 선택 [PXA USB Function support] 항목과 [Support for PXA USB network link function] 항목을 선택하고 설정 저장 'CoreBell LDS2000 X-scale Board' 항목이 선택이 되어있는지 확인 <LDS2000에서의 USB 드라이버 확인>
36
USB 컨트롤러 드라이버(계속) LDS2000의 IP 설정 USB 인터페이스에 임의의 IP 주소 설정
37
USB 컨트롤러 드라이버(계속) 호스트 PC의 모듈 컴파일 호스트 PC를 USB 서버로 동작하기 위해 커널의 기능 지정
커널 메뉴 [USB support] 선택, USB network 드라이버를 설정하고 저장 커널 Support for USB', 'UHCI (Intel PIIX, VIA, ...) support', 'UHCI Alternate Driver (JE) support', 'USB-to-USB Networking cables, Linux PDAs, ... (EXPERIMENTAL)' 네 항목을 모듈로 선택 <호스트의 USB케이블 연결시 정상 커널 메시지>
38
USB 컨트롤러 드라이버(계속) 호스트 PC의 IP 설정
호스트 PC에서 USB 네트워크 인터페이스 usb0에 적절한 IP 주소를 지정 <호스트의 USB 확인>
39
LDS2000 확장 보드 제어(계속) TFT LCD 출력 장치 제어
LDS2000은 640*480의 16비트 color를 지원하는 TFT LCD와 ADS7843 Touch Panel 장착 Tiny-X를 이용 LCD를 통한 GUI 구현 임베디드 시스템의 GUI 사용을 위해 X, QT, Micro Window 등이 이용됨 Tiny-X 설치 #cd [LDS2000-SW]/External/LCD/Tiny-X/xc #make World #make install
40
TFT LCD 출력 장치 제어(계속) 필요 library 설치 실행 파일 및 라이브러리 파일 복사
X Server 실행을 위한 PATH 지정 #ls /usr/local/LDS-ARM-Linux/lib ----- ltermcap, lflex 바이너리 파일 확인----- #cp [LDS2000-SW]/External/LCD/RefLIB/libtermcap* /usr/local/LDS-ARM-Linux/lib #cp [LDS2000-SW]/External/LCD/RefLIB/libfl* /usr/local/LDS-ARM-Linux/lib #cd /NFS #cp -R /usr/X11R6-arm usr/ #vi /NFS/root/.bashrc PATH=$PATH:/usr/X11R6-arm/bin LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/X11R6-arm/lib export PATH LD_LIBRARY_PATH
41
TFT LCD 출력 장치 제어(계속) 프레임 버퍼 디바이스 노드 추가 터치스크린 디바이스 생성 커널 부팅 후 X 서버 실행
#cp –dpR /dev/fb0 /NFS/dev/fb0 #ln –sf dev/fb0 dev/fb #mknod /NFS/dev/ts c 16 0 bin]$ Xlds2000 &
42
LDS2000 확장 보드 제어(계속) 사운드 장치 제어 PXA255에 내장된 AC97 Controller를 사운드 장치로 사용
코덱은 CIRRUS LOGIC의 CS4297A를 사용 커널 설정 최상위 메뉴의‘Sound’에서‘Sound support’항목 설정 확장되는 메뉴에서‘Intel PXA250/210 AC97 audio’항목 선택 사운드 플레이와 볼륨제어를 위해 splay와 smixer 사용
43
사운드 장치 제어(계속) splay 설치 smixer 설치
# cd [LDS2000-SW]/External/Sound/Splay-0.8.2 # make clean # ./configure # make CC=arm-linux-gcc CXX=arm-linux-c++ # cd [LDS2000-SW]/External/Sound/Splay-0.8.2/src/splay # ls # cd [LDS2000-SW]/External/Sound/smixer # make clean # make # ls
44
사운드 장치 제어 사운드 디바이스 노드 추가 smixer 환경 설정 후 splay 동작 주의점
생성된 splay, smixer, smixer.conf 파일을 /NFS 폴더에 복사 # cp –dpR /dev/dsp /NFS/dev/dsp 또는 # mknod c 14 3 /NFS/dev/dsp # cp –dpR /dev/mixer /NFS/dev/mixer 또는 # mknod c 14 0 /NFS/dev/mixer /]$ smixer –s /etc/smixer.conf /]$ splay /home/Sample.mp3
45
시리얼 통신 프로그래밍 시리얼 통신을 이용한 minicom 구현
시리얼 포트를 통해 비정규 모드에서 명령을 전송하고 데이터를 읽어 화면에 출력 #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> #include <fcntl.h> #include <termios.h> void butify_output(char *rbuff); /* 타겟에서 받은 데이터를 출력하기 좋게 변형 */ int main(int argc, char *argv[]) { int fd, nret, status; pid_t pid; /* ① 터미널을 제어하기 위해 termios 변수 선언 */ struct termios oldtios, newtios; char rbuff[1024], wbuff[1024];
46
<termios 구조체 구성>
minicom 구현(계속) <termios 구조체 구성> #define NCCS 32 struct termios { tcflag_t c_iflag; /* 입력모드 플래그 */ tcflag_t c_oflag; /* 출력모드 플래그 */ tcflag_t c_cflag; /* 제어모드 플래그 */ tcflag_t c_lflag; /* 로컬모드 플래그 */ cc_t c_line; /* 라인 규칙(POSIX는 미사용) */ cc_t c_cc[NCCS]; /* 제어 문자들 */ speed_t c_ispeed; /* 입력 속도 */ speed_t c_ospeed; /* 출력 속도 */ }; fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY); /* 시리얼 포트 개방 */ tcgetattr(fd, &oldtios); /* 현재 시리얼 포트의 설정을 보관 */ <open() 함수>
47
<termios 구조체 설정>
minicom 구현(계속) <termios 구조체 설정> ① memset(&newtios, 0x00, sizeof(newtios)); ② newtios.c_cflag = B9600 | CS8 | CLOCAL | CREAD; ③ newtios.c_iflag = IGNPAR | ICRNL; /* 패리티 에러 무시, CR은 NL로 변환 */ ④ newtios.c_oflag = 0; /* 사용되지 않는다. */ ⑤ newtios.c_lflag = 0; /* 비 정규 모드(canonical mode) */ ⑥ newtios.c_cc[VTIME] = 5; /* 타임아웃을 0.5초로 설정 */ ⑦ newtios.c_cc[VMIN] = 0; /* 사용되지 않는다. */ <정규모드로 설정> newtios.c_lflag = ICANON; /* 정규 모드(canonical) */ newtios.c_cc[VEOF] = 10; /* 줄 단위 구분 문자는 LF(Line Feed) */ newtios.c_cc[VMIN] = 1; /* 최소 1문자 입력때까지 read에서 대기 */ <tcflush() 함수> tcflush(fd, TCIFLUSH); tcsetattr(fd, TCSANOW, &newtios);
48
< butify_optput()>
minicom 구현(계속) <부모 프로세스> if ((pid = fork()) > 0) { /* parent */ while (1) { nret = read(fd, &rbuff, 1024); /* 읽기 작업 수행 */ rbuff[nret] = '\0'; /* 받은 데이터를 C-String으로 변환 */ butify_output(rbuff); /* 출력하기 좋은 형태로 데이터 변환 */ printf("%s", rbuff, nret); fflush(stdout); /* 받은 데이터를 터미널에 모두 출력 */ /* 자식 프로세스가 죽으면 종료 */ if (waitpid(pid, &status, WNOHANG)) { printf("Exiting parent\n"); break; } } } < butify_optput()> void butify_output(char *rbuff) { while (*rbuff != '\0') { if (!strncmp(rbuff, "\n\n", 2)) *rbuff = ' '; ++rbuff; } }
49
minicom 구현(계속) else if (pid == 0) { //child
<부모 프로세스> else if (pid == 0) { //child while (1) { nret = 0; while (wbuff[nret-1] != '\n' && nret <= 1024) /* 사용자 입력 */ wbuff[nret++] = getchar(); wbuff[nret] = '\0'; write(fd, &wbuff, nret); /* /x 나 /X를 입력받으면 프로그램 종료 if (!strncmp(wbuff, "/X\n\0", 4) || !strncmp(wbuff, "/x\n\0", 4)) { printf("Exiting child\n"); break; } } exit(0); } <부모 프로세스> tcsetattr(fd, TCSANOW, &oldtios); close(fd); return 0; }
50
시리얼 통신 프로그래밍(계속) mini-minicom 실행 모니터링 실험을 위해 프로그램 수행
# gcc -o mini-minicom mini-minicom.c # ./mini-minicom
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.