1 11 장 lds2000 임베디드 실습. 2 led hardware cs2 단자에 연결된 led 제어...

50
1 11 장 LDS2000 장장장장 장장

Upload: antonia-chase

Post on 17-Jan-2016

229 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

1

11 장 LDS2000 임베디드 실습

Page 2: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

2

LED Hardware

• CS2 단자에 연결된 LED 제어 레지스터는 0x08000008에 위치

• CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

<LED 의 하드웨어 흐름 >

Page 3: 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

< 가상 어드레스에 의한 LED 제어 응용 프로그램 >

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>

Page 4: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

4

KEYPAD Hardware• KEYPAD IN, KEYPAD OUT

레지스터를 이용 , KEYPAD 제어

• KEYPAD IN 레지스터– 데이터 D0 D1 D2로 3

개의 열을 구분– A3,A1은 1, A2,A0는 0

의 값을 가질 때 , 즉 옵셋 0x0A 로 접근

• KEYPAD OUT 레지스터– 지정된 열에서 눌러진 4

개의 키를 구분– A0,A1이 0, A2,A3이 1

의 값을 가질 때 , 즉 옵셋 0x0C로 접근

<KEYPAD 의 하드웨어 흐름과 비트구성 >

Page 5: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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

< 전역 변수 / 함수 선언 >

Page 6: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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

<keypad 제어 레지스터 접근을 위한 가상 주소 영역 설정과 해제 >

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

Page 7: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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

< 열기 / 닫기 처리 함수 >

Page 8: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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

Page 9: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

9

KEYPAD 제어를 위한 응용 프로그램

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

Page 10: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

10

KEYPAD 를 이용한 인터럽트 처리• KEYPAD의 인터럽트 발생

– KEYPAD OUT 레지스터의 출력된 키 데이터를 OR 연산

– 연산 값과 KEYPAD IN 레지스터의 D3와 NAND 연산 후 CPU 인터럽트 입력

• LDS2000에서는 KEYPAD의 인터럽트 선을 GP14에 연결

<KEYPAD 의 인터럽트 흐름 >< 인터럽트 발생 조건 >

Page 11: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

11

GPIO(General-Purpose I/O)

<PXA255 Block Daigram>

• 일반적인 용도로 사용 가능한 디지털 입출력 기능의 Port pin들임

• PXA255 의 GPIO 는 총 85 개이며 각각의 핀들은 입력 또는 출력으로 프로그램 될 수 있다 .

• 핀이 입력으로 사용되면 인터럽트 소스의 기능도 수행이 가능하다 .

• PXA255 의 대부분의 GPIO 는 단순히 디지털 입출력 뿐만 아니라 부가적인 기능을 갖고 있다 .

• 부가적인 기능과 단순 IO 는 함께 사용할 수 없기 때문에 하드웨어 설계시 유의해야 한다 .

Page 12: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

12

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>

Page 13: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

13

인터럽트 처리• 인터럽트 처리

– 일반적으로 인터럽트에 등록된 핸들러 함수에서 처리

– 인터럽트 처리 작업이 많을 경우 bottom half 방식으로 처리

• Bottom half 방식– 인터럽트 핸들러 함수는

태스크 호출 후 종료– 실제적인 인터럽트

처리는 태스크 형태로 처리하도록 수행되는 기법

<bottom half 처리 흐름 >

Page 14: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

14

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

KEYPAD 인터럽트 제어 모듈 헤더 파일과 함수 선언

Page 15: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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

Page 16: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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

< 인터럽트 핸들러 등록함수 > < 플래그 설정 정보 >

•인터럽트 함수 등록

Page 17: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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

Page 18: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

18

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

Page 19: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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

Page 20: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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

< 인터럽트 핸들러 함수 >

Page 21: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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; switch (*KEYPAD_OUT_RegPtr) { 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; default : break; } *KEYPAD_IN_RegPtr = 0x04; switch (*KEYPAD_OUT_RegPtr) { 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; default : break; }finish: *KEYPAD_IN_RegPtr = 0x0F;}

Page 22: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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

•모듈의 인터럽트 처리에 의해 키 값을 읽어오고 있으므로 별도의 읽기 , 쓰기가 불필요

Page 23: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

23

LED 와 KEYPAD 동시 제어

• KEYPAD로부터 눌린 키를 받아 그에 해당하는 LED를 점등하는 응용 프로그램 작성

< 응용 프로그램과 디바이스 드라이버의 처리 흐름 >

Page 24: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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

Page 25: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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

Page 26: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

26

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

Page 27: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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

Page 28: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3: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", key[0]); break; default: printf("%c-th LED ON :: key=%c\n", key[0], key[0]); break; } /* 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;}

Page 29: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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

< 연동제어 응용 프로그램 ( 계속 )>

Page 30: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

30

LDS2000 확장 보드 활용• LDS2000 확장보드

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

Page 31: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

31

LDS2000 확장 LED 출력 제어

< 확장보드 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;}

Page 32: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

32

7-Segment LED 제어• 5개의 7-segment• 표현 값은 8비트 제어

레지스터에 의해 결정– 상위 4비트 :5개의 7-segment 구분

– 하위 4비트 : 지정된 세그먼트 LED 십진 숫자 결정

<7-Segment 제어 레지스터의 비트 구성 >

Page 33: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

33

7-segment LED 출력 장치 제어

<7-Segment 제어 프로그램 >

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

Page 34: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

34

LDS2000 확장 보드 제어 ( 계속 )

• USB 컨트롤러 드라이버– USB 를 연결을 이용한 TCP/IP 연결 실습– LDS2000 에서는 USB Server 와 Client 지원–커널에서 제공하는 드라이버를 이용하여 USB 드라이버 실습

Page 35: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

35

USB 컨트롤러 드라이버 ( 계속 )

• LDS2000 의 커널 컴파일– [System type], [Intel PXA250/210 Implementations] 순서로

선택– [PXA USB Function support] 항목과 [Support for PXA USB n

etwork link function] 항목을 선택하고 설정 저장– 'CoreBell LDS2000 X-scale Board' 항목이 선택이 되어있는지

확인

<LDS2000 에서의 USB 드라이버 확인 >

Page 36: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

36

USB 컨트롤러 드라이버 ( 계속 )

• LDS2000의 IP 설정– USB 인터페이스에 임의의 IP 주소 설정

<LDS2000 의 IP 설정 >

Page 37: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

37

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 케이블 연결시 정상 커널 메시지 >

Page 38: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

38

USB 컨트롤러 드라이버 ( 계속 )

•호스트 PC의 IP 설정–호스트 PC에서 USB 네트워크 인터페이스 usb0에 적절한 IP 주소를 지정

< 호스트의 USB 확인 >

Page 39: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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

Page 40: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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/binLD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/X11R6-arm/libexport PATH LD_LIBRARY_PATH

Page 41: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

41

TFT LCD 출력 장치 제어 ( 계속 )

•프레임 버퍼 디바이스 노드 추가

•터치스크린 디바이스 생성

•커널 부팅 후 X 서버 실행

#cp –dpR /dev/fb0 /NFS/dev/fb0#ln –sf dev/fb0 dev/fb

#mknod /NFS/dev/ts c 16 0

[[email protected] bin]$ Xlds2000 &

Page 42: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

42

LDS2000 확장 보드 제어 ( 계속 )

•사운드 장치 제어– PXA255 에 내장된 AC97 Controller 를 사운드 장치로 사용

–코덱은 CIRRUS LOGIC 의 CS4297A 를 사용–커널 설정 최상위 메뉴의‘ Sound’ 에서‘ Sound support’ 항목 설정

–확장되는 메뉴에서‘ Intel PXA250/210 AC97 audio’ 항목 선택

–사운드 플레이와 볼륨제어를 위해 splay 와 smixer 사용

Page 43: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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

Page 44: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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

[[email protected] /]$ smixer –s /etc/smixer.conf[[email protected] /]$ splay /home/Sample.mp3

Page 45: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

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

Page 46: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

46

minicom 구현 ( 계속 )

<termios 구조체 구성 >

#define NCCS 32struct 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() 함수 >

Page 47: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

47

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

Page 48: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

48

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

Page 49: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

49

minicom 구현 ( 계속 )

< 부모 프로세스 >

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

Page 50: 1 11 장 LDS2000 임베디드 실습. 2 LED Hardware CS2 단자에 연결된 LED 제어 레지스터는 0x08000008 에 위치 CS2 가 1 이고 A0-A2:0, A3:1 일 때 레지스터 접근

50

시리얼 통신 프로그래밍 ( 계속 )

• mini-minicom 실행–모니터링 실험을 위해 프로그램 수행

# gcc -o mini-minicom mini-minicom.c# ./mini-minicom

<mini-minicom 실행 화면 >