• 검색 결과가 없습니다.

(Embedded System Programming) ESP30076 임베디드시스템프로그래밍

N/A
N/A
Protected

Academic year: 2022

Share "(Embedded System Programming) ESP30076 임베디드시스템프로그래밍"

Copied!
18
0
0

로드 중.... (전체 텍스트 보기)

전체 글

(1)

Module 14: Kernel Timer

ESP30076 임베디드 시스템 프로그래밍 (Embedded System Programming)

조 윤 석 전산전자공학부

(2)

 리눅스에서 커널 타이머 사용법 알아보기

– HZ, jiffies_64, struct timer_list

 커널 타이머를 활용한 하드웨어 제어용 디바이스 드라이버 작성

주차별 목표

(3)

 HZ

– 리눅스 커널에서 주기적으로 발생하는 시스템 타이머 interrupt 횟수

– 1초에 HZ 상수값만큼 발생

– (예) HZ=100, 1초에 system timer interrupt 100번 발생 – #include <linux/timer.h>

• #define HZ 100 // <asm/param.h>

 jiffies_64

– 리눅스 커널에서 제공하는 global variable – 커널 전체에서 동일한 기준 시간값 제공

– Scheduling 구현을 위해 timer interrupt가 필요하고, 리눅 스 커널은 HZ라는 상수값을 초기에 설정함

Timer 관련 변수

(4)

 Timer interrupt 관련

– HZ: 1초당 발생되는 timer interrupt 횟수 – USER_HZ: HZ 값을 보정하는 수

– jiffies: 커널 2.4에서 초당 HZ 값 만큼 증가하는 전역변수 – jiffies_64: 커널 2.6에서 초당 HZ 값 만큼 증가하는 전역변

– get_jiffies_64(): jiffies_64 값을 참조하기 위한 함수

 HZ

– ARM: 100/128/200/1000 – i386: 1000

– x86-64: 1000 – MIPS: 100/128

get_jiffies_64()

(5)

 struct timer_list

#include <linux/timer.h>

struct timer_list { /* ... */

unsigned long expires;

void (*function)(unsigned long);

unsigned long data;

};

 Kernel drivers with a number of functions to declare, register, and remove kernel timers

– void init_timer(struct timer_list *timer);

– struct timer_list TIMER_INITIALIZER(_function, _expires, _data);

– void add_timer(struct timer_list * timer);

– int del_timer(struct timer_list * timer);

Timer API

(6)

 <linux/timer.h>

struct timer_list { /*

* All fields that change during normal runtime grouped to the

* same cacheline

*/

struct list_head entry;

unsigned long expires; /* the timeout, in jiffies */

struct tvec_base *base;

void (*function)(unsigned long); /* handler of the timeout */

unsigned long data; /* argument to the handler */

int slack;

};

timer_list

(7)

 LED 구동 시나리오

– 응용프로그램의 인자가 1

• 8개의 LED가 0.5초 단위로 지속적으로 점멸됨

• # ./test_timer_led 1

– 응용프로그램의 인자가 0

• 모든 LED를 끔

• # ./test_timer_led 0

 파일명

– 응용프로그램: test_timer_led.c

– 디바이스드라이버: led_timer_driver.c – 디바이스 노드: /dev/led_timer_device – Major number: 247

일정주기로 LED 점멸되는 드라이버 작성

(8)

 Timer로 구동되는 LED 관리 구조체

– KERNEL_TIMER_STRUCT

type struct {

struct timer_list timer;

unsigned long led_state;

} __attribute__((packed)) KERNEL_TIMER_STRUCT;

– ptimermgr: LED 상태와 timer를 관리하기 위한 구조체

• led_state는 LED 점멸을 결정하기 위한 상태 변수값임

• Timer handler에 argument를 timer 구조체 주소로 지정하는데, LED 점멸을 위해 led 상태값(여기서는 led_sate임)도 같이 보내기 위해 추가 구조체를 생성하고, 그 구조체 주소값을 argument로 보냄

구조체 정의

(9)

흐름도

led_timer_init()

- register_chrdev() - ioremap()

- ptimermgr 선언 - init ptimermgr

- led_timer_register()

led_timer_register() - init_timer()

- add_timer()

led_timer_timeover()

- LED blinking if led_blink=1 - LED off if led_blink=0

- led_timer_register()

사용자 system call write(fd, arg, count)

- led_blink = arg(0 or 1) led_timer_exit()

- LED turn off - del_timer()

- kfree(ptimermgr) - iounmap()

- unregister_chrdev()

% insmod led_timer_driver.ko

(10)

root@esp:~# mkdir /root/work/dd/kernel_timer_led root@esp:~# cd /root/work/dd/kernel_timer_led

root@esp:~/work/dd/kernel_timer_led# vi led_timer_driver.c

타이머 연동 LED 구동 디바이스 드라이버 (led_timer_driver.c)

/* LED Kernel Timer Example FILE: led_timer_driver.c */

#ifndef __LED_KERNEL_TIMER_DRIVER_

#define __LED_KERNEL_TIMER_DRIVER_

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/fs.h>

#include <linux/module.h>

#include <asm/io.h>

#include <asm/uaccess.h>

#include <linux/errno.h>

#include <linux/types.h>

#include <linux/fcntl.h>

#include <linux/slab.h> /* kmalloc() */

#include <linux/timer.h> /* HZ */

typedef struct {

struct timer_list timer;

unsigned long led_state;

} __attribute__((packed)) KERNEL_TIMER_STRUCT;

#endif

#define DEV_NAME "led_timer_device"

#define IOM_LEDTIMER_MAJOR_NUM 247

(11)

led_timer_driver.c (2)

static int ledport_usage = 0;

static unsigned char *iom_led_addr;

static KERNEL_TIMER_STRUCT *ptimermgr = NULL;

static unsigned char led_blink = 0;

MODULE_LICENSE("GPL");

MODULE_AUTHOR("HGU");

int led_timer_init(void);

void led_timer_exit(void);

module_init(led_timer_init);

module_exit(led_timer_exit);

void led_timer_timeover(unsigned long arg); /* timer.function */

void led_timer_register(KERNEL_TIMER_STRUCT *pdata, unsigned long timeover);

int led_timer_open (struct inode *, struct file *);

int led_timer_release (struct inode *, struct file *);

ssize_t led_timer_write (struct file *, const char __user *, size_t, loff_t *);

struct file_operations led_timer_fops = { .owner = THIS_MODULE,

.open = led_timer_open, .release = led_timer_release, .write = led_timer_write, };

(12)

led_timer_driver.c (3)

int __init led_timer_init(void) { int major_num;

major_num = register_chrdev(IOM_LEDTIMER_MAJOR_NUM, DEV_NAME, &led_timer_fops);

if ( major_num < 0 ) {

printk(KERN_WARNING"%s: can't get or assign major number %d\n", DEV_NAME, IOM_LEDTIMER_MAJOR_NUM);

return major_num;

}

printk("Success to load the device %s. Major number is %d\n", DEV_NAME, IOM_LEDTIMER_MAJOR_NUM);

iom_led_addr = ioremap(IOM_LED_ADDRESS, 0x1);

ptimermgr = kmalloc(sizeof(KERNEL_TIMER_STRUCT), GFP_KERNEL);

/* GFP_KERNEL: Normal allocation of kernel memory. May sleep */

/* GFP_KERNEL: __GFP_WAIT(스케줄러 선점가능), __GFP_IO(물리적IO가능), __GFP_FS(저수준 filesystem IO 가능) */

if ( ptimermgr == NULL ) return -ENOMEM;

memset(ptimermgr, 0, sizeof(KERNEL_TIMER_STRUCT)); // GFP_KERNEL | __GFP_ZERO (Kernel 2.6가능) led_timer_register(ptimermgr, TIME_STEP);

return 0;

}

(13)

led_timer_driver.c (4)

void led_timer_register(KERNEL_TIMER_STRUCT *pdata, unsigned long timeover) { /* init_timer(&timer) */

init_timer(&(pdata->timer)); /* timer API: void init_timer(struct timer_list *timer) */

pdata->timer.expires = get_jiffies_64() + timeover;

pdata->timer.function = led_timer_timeover; /* handler of the timeout */

pdata->timer.data = (unsigned long) pdata; /* argument to the handler */

add_timer(&(pdata->timer));

}

void led_timer_timeover(unsigned long arg) { KERNEL_TIMER_STRUCT *pdata = NULL;

pdata = (KERNEL_TIMER_STRUCT *) arg;

if(led_blink == BLINK_MODE) { /* blink */

pdata->led_state = ~(pdata->led_state);

if(pdata->led_state != 0)

outb(0x00, (unsigned int)iom_led_addr);

elseoutb(0xff, (unsigned int)iom_led_addr);

}else

outb(0xff, (unsigned int)iom_led_addr); /* turn off LED */

(14)

led_timer_driver.c (5)

int led_timer_open (struct inode *inode, struct file *filp) { if(ledport_usage)

return -EBUSY;

ledport_usage = 1;

return 0;

}

int led_timer_release (struct inode *inode, struct file *filp) { ledport_usage = 0;

return 0;

}

ssize_t led_timer_write (struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { if (copy_from_user(&led_blink, buf, count))

return -EFAULT;

return count;

}

void __exit led_timer_exit(void)

{ outb(0xff, (unsigned int)iom_led_addr); /* LED turn off */

if(ptimermgr != NULL ) {

del_timer(&(ptimermgr->timer));

kfree(ptimermgr);

(15)

root@esp:~/work/dd/kernel_timer_led# vi test_timer_led.c

타이머 연동 LED 구동 응용 프로그램 (test_timer_led.c)

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#define DEV_NAME "/dev/led_timer_device"

int main(int argc, char **argv) { int led_fd;

unsigned char led_blink;

if ( argc != 2 ) {

printf("Usage: %s [0 or 1] (0: all LED OFF, 1: LED blinking)\n", argv[0]);

return -1;

}

led_fd = open(DEV_NAME, O_WRONLY);

if ( led_fd < 0 ) {

printf("LED timer driver open error...\n");

return -1;

}

(16)

test_timer_led.c (2)

led_blink = (unsigned char) atoi(argv[1]);

printf("{A} input: %d\n", led_blink);

write(led_fd, &led_blink, sizeof(led_blink));

close(led_fd);

return 0;

}

(17)

% vi Makefile

% make

컴파일

CC = arm-linux-gcc

KDIR = /root/download/kernel-2.6.35 obj-m = led_timer_driver.o

PWD = $(shell pwd)

TEST_TARGET = test_timer_led TEST_SRCS = $(TEST_TARGET).c all: module test_pgm

module:

$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules test_pgm:

$(CC) $(TEST_SRCS) -o $(TEST_TARGET) clean:

rm -rf *.ko *.o

rm -rf *.symvers *.order *mod.c *.cmd rm -rf $(TEST_TARGET)

(18)

 타겟보드에서 실행

– Host 컴퓨터의 /root 디렉토리를 NFS로 연결

# cd /root/nfs/work/dd/kernel_timer_led

# insmod led_timer_driver.ko

# mknod /dev/led_timer_device c 247 0

# ./test_timer_led 1

# ./test_timer_led 0

실행

참조

관련 문서

void ShowPrefixTypeExp(BTreeNode * bt); // 전위 표기법 기반 출력 void ShowInfixTypeExp(BTreeNode * bt); // 중위 표기법 기반 출력 void ShowPostfixTypeExp(BTreeNode *

■ 컴파일러, JRE (Java Runtime Environment), 클래스 라이브러리, 샘플 등 포함..

typedef struct LinkedNode { Element data;.

타입 매개 변수 사용하지 않는 경우 경고 발생9. Vector&lt;Integer&gt; 로 타입 매개

size 바이트만큼의 메모리 공간을 할당하며 그 시작주소를 void* 형으로 반환한다..

case의 비교 값과 일치하는 것이 없으면 default 문 실행. default

Calculator 클래스를 사용하기 위해서는 패키지를 포함 하는 정확한 경로명을 컴파일러에게

[r]