11장 LDS2000 임베디드 실습.

Slides:



Advertisements
Similar presentations
Linux Serial Programming for POSIX Operating Systems
Advertisements

Lecture 101 Lecture 10: Kernel Modules and Device Drivers ECE 412: Microcomputer Laboratory.
Device Drivers. Linux Device Drivers Linux supports three types of hardware device: character, block and network –character devices: R/W without buffering.
RT_FIFO, Device driver.
Lecture for Lab 3, Exp1 of EE505 (Developing Device Driver) T.A. Chulmin Kim CoreLab. Mar, 11, 2011 [XenSchedulerPaper_Hotcloud-commits] r21 - /
Computer System Laboratory
The Practice of Micro-processor Yonam Institute of Digital Technology 06. LCD Control.
USERSPACE I/O Reporter: R 張凱富.
Terminal I/O POSIX termios Two terminal I/O modes Canonical and non-canonical Getting and setting terminal attributes Terminal window size: struct winsize.
Terminal Control operating systems. Terminal Control may seem like an arcane subject, but … It illustrates the relationship between devices and files.
Process in Unix, Linux and Windows CS-3013 C-term Processes in Unix, Linux, and Windows CS-3013 Operating Systems (Slides include materials from.
CS-502 Fall 2006Processes in Unix, Linux, & Windows 1 Processes in Unix, Linux, and Windows CS502 Operating Systems.
I/O April 16, 2002 Topics Files Unix I/O Standard I/O Reading: (Beta) or (New) Problems: 12.9 (Beta) or 12.4 (New) class24.ppt
Unix & Windows Processes 1 CS502 Spring 2006 Unix/Windows Processes.
Processes in Unix, Linux, and Windows CS-502 Fall Processes in Unix, Linux, and Windows CS502 Operating Systems (Slides include materials from Operating.
Computer System Laboratory
Loadable Kernel Modules Dzintars Lepešs The University of Latvia.
Kernel module programming Nezer J. Zaidenberg. reference This guide is built on top of The Linux Kernel Module Programming Guide The guide is available.
KyungHee Univ. 1-0 문자열 입 · 출력 프로그램 작성 예. KyungHee Univ. 1-1  모니터에 문자열 출력 하는 프로그램 작성  표준 출력 장치에 문자를 출력 하는 함수 함수의 기본형 : void SCI_OutChar(letter)  문자를.
Process in Unix, Linux, and Windows CS-3013 A-term Processes in Unix, Linux, and Windows CS-3013 Operating Systems (Slides include materials from.
AVR CPU Core & 8 bit AVR Instruction Set
Include/mango100.h 설명 망고 100 보드로 놀아보자 -7 cafe.naver.com/embeddedcrazyboys.
Bootloader 부트로더.
Codec,battery,powermanager 커널 드라이버
2012 내장형 시스템 설계  Full Color LED 디바이스 구성  Full Color LED 디바이스 드라이버  Full Color LED JNI 라이브러리 작성  Full Color LED 안드로이드 App 구현  JNI 라이브러리.
Hanyang Univ.  강의 목표 ◦ 임베디드 개발 환경의 이해  강의 내용 ◦ 교차 컴파일 환경 구축 및 부트로더 실습 Hanyang Univ.
Linux/UNIX Programming APUE (Introduction) 문양세 강원대학교 IT 대학 컴퓨터과학전공.
Operating Systems Chapter 2
Kernel Modules. Kernel Module Pieces of code that can be loaded and unloaded into the kernel upon demand. Compiled as an independent program With appropriate.
CS252: Systems Programming Ninghui Li Based on Slides by Prof. Gustavo Rodriguez-Rivera Topic 8: Opening Files and Starting Processes.
Implementation of Embedded OS Lab3 Linux Kernel Modules.
Stepper Motor 디바이스 드라이버
Lab 13 Department of Computer Science and Information Engineering National Taiwan University Lab13 – Interrupt + Timer 2014/12/23 1 /16.
Broadcasting and UDP Network Lab. 남 재 준. HANNAM UNIVERSITY 2 목 차  Broadcast UDP 소켓 설치  소켓을 사용하여 broadcast message 보내기  소켓을.
Interrupt. incoming Lab. Interrupt an asynchronous signal indicating the need for attention hardware interrupt/software interrupt call “interrupt service.
Linux Device Driver 2009/04/08. Reference Book Another Reference Book Embedded Linux Primer: A Practical, Real-World Approach By Christopher Hallinan.
Internal Device Driver
Interfacing Device Drivers with the Kernel
Ubiquitous Computing Practice - Part 4(RSSI) - Laboratory of Intelligent KUT ( Yong-hwan Kim Spring.
영상 획득 영상 저장 카메라 파라메터 커스텀 이미지
Lab 12 Department of Computer Science and Information Engineering National Taiwan University Lab12 – Driver 2014/12/16 1 /21.
COMP 3438 – Part I - Lecture 5 Character Device Drivers
망고100 보드로 놀아보자-14 디바이스 드라이버 작성 기초
Introduction to FUSE (File system in USEr space) Speaker:Zong-shuo Jheng Date:March 14, 2008.
ISLab Flash Team Ch 3. Kernel-Mode I/O Processing.
Chapter 7. Pipe 2 pipe 개요  Simple IPC (inter process communication) mechanism  두 프로세스간 통신 기능 제공  동작 방식  수도관 (pipe) 을.
Embedded System Lab. II DMA Programming in Linux 경희대학교 컴퓨터공학과 조 진 성.
CS241 Systems Programming Discussion Section Week 2 Original slides by: Stephen Kloder.
안양대학교 전기전자공학과 서 삼 준 Kernel Fusing (Boot Loader & tftp 활용 )
Chap.6.3 UART.
Using Linux with ARM Tutorial #3.
 Backlight 에서 나온 백색광이 액정 셀을 통과하면 서 투과율이 조절되고 red, green, blue 의 color filter 를 투과해 나오는 빛의 혼합을 통해 색이 구 성됨  Color filter 는 셀사이의 빛을 차단하는 black matrix,
Lecture 3 Module Programming and Device Driver (Homework#1 included) Kyu Ho Park Sept. 15, 2015.
실험 구성 (DC모터 속도제어) -Matlab xPC Target 이용
MVL3.0 설치를 위한 Cross 환경 설정 구 본 진. Contents  IXDP425 보드 소개  Cross 개발 환경 구축.
 LED 를 직접 제어하는 디바이스 드라이버를 작성해 보자  Reminder: LED 는 SPI 를 통해 ARM7 과 연결된다. ◦ 그렇다면 고쳐야 하는 코드는 어디에 ?  linux-2.6.x/arch/arm/mach-nds/arm7 ◦ Hardware spec.
Device Driver_Skeleton
Lecture 3 Module Programming and Device Driver (Homework#1 included)
Protection of System Resources
Computer System Laboratory
Linux Kernel Driver.
Processes in Unix, Linux, and Windows
More on UART Interrupts; System Calls
Processes in Unix, Linux, and Windows
Implementation of Embedded OS
Computer System Laboratory
Processes in Unix, Linux, and Windows
Processes in Unix and Windows
Loadable Kernel Modules
Presentation transcript:

11장 LDS2000 임베디드 실습

LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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, 1024, (PROT_READ|PROT_WRITE), MAP_SHARED, LED_fd, 0x08000000); /* CS2 */          LEDReg = (unsigned char *)(mmap_addr + 0x08); /* 0x8000008 */     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제어 응용 프로그램>

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의 하드웨어 흐름과 비트구성>

<모듈의 처리 함수 구조체 선언> 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, }; <모듈의 처리 함수 구조체 선언> <전역 변수/함수 선언>

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)0x08000000, (unsigned int)(1024));   /* get virtual address for KEYPAD control register */     /* 0xA offset from base ptr, (0x0800000A) */     KEYPAD_IN_RegPtr = KEYPAD_BasePtr + 0x0A;     /* 0xC offset from base ptr, (0x0800000C) */     KEYPAD_OUT_RegPtr = KEYPAD_BasePtr + 0x0C;     return 0; } void KEYPAD_virtual_memory_free() { iounmap(KEYPAD_BasePtr); <모듈의 등록과 해제 함수> <keypad 제어 레지스터 접근을 위한 가상 주소 영역 설정과 해제>

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; } < 열기/닫기 처리 함수>

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; } < 쓰기/읽기 처리 함수>

<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 제어용 응용 프로그램>

KEYPAD를 이용한 인터럽트 처리 KEYPAD의 인터럽트 발생 KEYPAD OUT 레지스터의 출력된 키 데이터를 OR 연산 연산 값과 KEYPAD IN 레지스터의 D3와 NAND 연산 후 CPU 인터럽트 입력 LDS2000에서는 KEYPAD의 인터럽트 선을 GP14에 연결 < 인터럽트 발생 조건> <KEYPAD의 인터럽트 흐름>

GPIO(General-Purpose I/O) 일반적인 용도로 사용 가능한 디지털 입출력 기능의 Port pin들임 PXA255의 GPIO는 총 85개이며 각각의 핀들은 입력 또는 출력으로 프로그램 될 수 있다. 핀이 입력으로 사용되면 인터럽트 소스의 기능도 수행이 가능하다. PXA255의 대부분의 GPIO는 단순히 디지털 입출력 뿐만 아니라 부가적인 기능을 갖고 있다. 부가적인 기능과 단순 IO는 함께 사용할 수 없기 때문에 하드웨어 설계시 유의해야 한다. <PXA255 Block Daigram>

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>

인터럽트 처리 인터럽트 처리 Bottom half 방식 일반적으로 인터럽트에 등록된 핸들러 함수에서 처리 인터럽트 핸들러 함수는 태스크 호출 후 종료 실제적인 인터럽트 처리는 태스크 형태로 처리하도록 수행되는 기법 <bottom half 처리 흐름 >

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

전역 설정: 인터럽트 제어를 위한 구조체 모듈의 처리 함수 구조체 선언 큐 생성 및 태스크 등록 전역 설정: 인터럽트 제어를 위한 구조체 모듈의 처리 함수 구조체 선언 큐 생성 및 태스크 등록  /* 키 값을 알아내기 위한 코드는 인터럽트 처리 함수에 존재*/ 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 */  

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"); <플래그 설정 정보> <인터럽트 핸들러 등록함수>

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

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 8 /* 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

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

인터럽트 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()가 호출될 때 실행되는 실제 함수>

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;

< 인터럽트 처리 응용 프로그램> 모듈의 인터럽트 처리에 의해 키 값을 읽어오고 있으므로 별도의 읽기, 쓰기가 불필요 < 인터럽트 처리 응용 프로그램> #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; } 

LED 와 KEYPAD 동시 제어 KEYPAD로부터 눌린 키를 받아 그에 해당하는 LED를 점등하는 응용 프로그램 작성 <응용 프로그램과 디바이스 드라이버의 처리 흐름>

연동 제어를 위한 모듈 #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); <헤더 파일과 함수 선언>

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)0x8000000, (unsigned int)(1024));     /* 0 offset from base ptr, ( 0x8000008 ) */     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); <가상 주소 영역 설정과 해제>

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

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(3500000); /* 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; } <쓰기/읽기 처리 함수소스>

연동 제어를 위한 응용 프로그램 #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; } <연동제어 응용 프로그램>

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; } <연동제어 응용 프로그램(계속)>

LDS2000 확장 보드 활용 LDS2000 확장보드 <LDS2000 확장보드의 블록 다이어그램>

<확장보드 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, 0x14100000); /* CS5_Base + 0x100000 */     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 제어 프로그램>

<7-Segment 제어 레지스터의 비트 구성> 7-Segment LED 제어 5개의 7-segment 표현 값은 8비트 제어 레지스터에 의해 결정 상위 4비트:5개의 7-segment 구분 하위 4비트: 지정된 세그먼트 LED 십진 숫자 결정 <7-Segment 제어 레지스터의 비트 구성>

<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, 0x14080000); /* 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 제어 프로그램>

LDS2000 확장 보드 제어(계속) USB 컨트롤러 드라이버 USB를 연결을 이용한 TCP/IP 연결 실습 LDS2000에서는 USB Server와 Client 지원 커널에서 제공하는 드라이버를 이용하여 USB 드라이버 실습

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 드라이버 확인>

USB 컨트롤러 드라이버(계속) LDS2000의 IP 설정 USB 인터페이스에 임의의 IP 주소 설정

USB 컨트롤러 드라이버(계속) 호스트 PC의 모듈 컴파일 호스트 PC를 USB 서버로 동작하기 위해 커널의 기능 지정 커널 메뉴 [USB support] 선택, USB network 드라이버를 설정하고 저장 커널 2.4.18-8 Support for USB', 'UHCI (Intel PIIX, VIA, ...) support', 'UHCI Alternate Driver (JE) support', 'USB-to-USB Networking cables, Linux PDAs, ... (EXPERIMENTAL)' 네 항목을 모듈로 선택 <호스트의 USB케이블 연결시 정상 커널 메시지>

USB 컨트롤러 드라이버(계속) 호스트 PC의 IP 설정 호스트 PC에서 USB 네트워크 인터페이스 usb0에 적절한 IP 주소를 지정 <호스트의 USB 확인>

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

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

TFT LCD 출력 장치 제어(계속) 프레임 버퍼 디바이스 노드 추가 터치스크린 디바이스 생성 커널 부팅 후 X 서버 실행 #cp –dpR /dev/fb0 /NFS/dev/fb0 #ln –sf dev/fb0 dev/fb #mknod  /NFS/dev/ts c 16 0 [root@192.168.0.12 bin]$ Xlds2000 &

LDS2000 확장 보드 제어(계속) 사운드 장치 제어 PXA255에 내장된 AC97 Controller를 사운드 장치로 사용 코덱은 CIRRUS LOGIC의 CS4297A를 사용 커널 설정 최상위 메뉴의‘Sound’에서‘Sound support’항목 설정 확장되는 메뉴에서‘Intel PXA250/210 AC97 audio’항목 선택 사운드 플레이와 볼륨제어를 위해 splay와 smixer 사용

사운드 장치 제어(계속) 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

사운드 장치 제어 사운드 디바이스 노드 추가 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 [root@192.168.0.12 /]$ smixer –s /etc/smixer.conf [root@192.168.0.12 /]$ splay /home/Sample.mp3

시리얼 통신 프로그래밍 시리얼 통신을 이용한 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];

<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() 함수>

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

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

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

시리얼 통신 프로그래밍(계속) mini-minicom 실행 모니터링 실험을 위해 프로그램 수행 # gcc -o mini-minicom mini-minicom.c # ./mini-minicom