행복한 하루
Raspberry Pi – Linux Device Driver 만들어 보기-8 ( Timer를 이용한 LED 제어 ) 본문
Raspberry Pi – Linux Device Driver 만들어 보기-8 ( Timer를 이용한 LED 제어 )
변화의 물결 2022. 12. 30. 00:05
안녕하세요.
이번에는 Timer를 사용하는 방법을 확인해보려고 합니다. 드라이버가 추가되면 LED가 켜지고 타이머가 초기화 4초 초기화되면서 카운트하기 시작합니다. 시간이 되면 LED가 꺼지는 것을 테스트해 봅니다.
1. 하드웨어 연결
- 간단한 점퍼 케이블과 LED 하나 정도만 있으면 됩니다. 안전하게 테스트 위해서는 브래드 보드에 220Ω~330Ω정도 저항 뒤에 LED를 달아서 테스트해야 합니다.
- 라즈베리파이의 GPIO 4 핀에는 LED +극(Anode), Ground핀에는 LED -극(Cathode)을 연결합니다.
2. 사전 작업
- 기존에 작업한 것처럼 드라이버 구조가 만들어진 소스를 이용합니다. day1에서 기초 형태를 복사합니다.
pi@raspberrypi:~/DriverStudy $ cp -r day1 day8_timer
pi@raspberrypi:~/DriverStudy $ cd day8_timer/
pi@raspberrypi:~/DriverStudy/day8_timer $ ls
pi@raspberrypi:~/DriverStudy/day8_timer $ mv day1_module.c day8_timer.c
- Makefile에서 컴파일될 파일 이름을 변경합니다.
pi@raspberrypi:~/DriverStudy/day8_timer $ vim Makefile
obj-m += day8_timer.o
3. 소스 추가
1) 타이머를 이용한 헤더파일을 추가합니다.
#include <linux/gpio.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
...
MODULE_DESCRIPTION("A simple timer Test");
2) 기존의 GPIO 내용(day4_gpio)에서 gpio 초기화하는 부분들을 복사해서 리턴값만 -1로 변경해서 사용합니다.
- static int __init ModuleInit(void) 함수에 추가
/* GPIO 4 init */
if(gpio_request(4, "rpi-gpio-4")) {
printk("Can not allocate GPIO 4\n");
return -1;
}
/* Set GPIO 4 direction */
if(gpio_direction_output(4, 0)) {
printk("Can not set GPIO 4 to output!\n");
gpio_free(4);
return -1;
}
/* Trun LED on */
gpio_set_value(4,1);
- static void __exit ModuleExit(void) 함수에서 해제해 줍니다.
gpio_free(4);
3) 타이머를 위한 구조체를 전역변수로 선언하고 타이머 시간이 되었을 때 실행되는 콜백함수를 구현해 줍니다. 예제에서는 LED가 꺼지는 동작을 합니다.
/** variable for timer */
static struct timer_list my_timer;
void timer_callback(struct timer_list * data) {
gpio_set_value(4, 0); /* Turn LED off */
}
4) 타이머 구조체를 초기화 및 시간을 설정하는 것을 ModuleInit 함수에서 구현합니다.
- timer_list 구조체 안에 expires 변수가 있는데 이것은 타이머가 만료되는 시간을 가지며 jiffies + @ 값으로 된다고 합니다. 그리고 콜백함수를 가지는 함수포인터 변수도 가지고 있고, 타이머 속성을 가지는 flags도 변수로 가지고 있습니다.
- timer_setup 함수로 초기화를 하고 mod_timer 함수로 커널에 타이머를 등록합니다. (혹은 add_timer 함수 이용)
- 참조 블로그 글에서 타이머가 정확하지 않을 수 있으나 최대한 expires 맞추려고 한다고 합니다. 다음 내용에서 좀 더 정확한 타이머를 다룰 예정입니다.
- msecs_to_jiffies() 함수에 인자로 원하는 시간(ms 단위)을 넣어주면 타이머가 원하는 시간에 콜백함수를 호출하게 됩니다. 여기서 jiffies는 cpu 클럭을 이용한 커널 타이머 실행 시간 단위라고 보시면 어떨까 합니다. 내용이 산으로 갈 것 같아서 참고 사이트 링크를 참고하시면 도움이 될 거라고 생각됩니다.
/* Initialize timer */
timer_setup(&my_timer, timer_callback, 0);
mod_timer(&my_timer, jiffies + msecs_to_jiffies(4000));
5) 드라이버 해제 시 ModuleExit 함수에서 타이머를 제거합니다. 위에서 생성된 타이머가 timeout 되어 실행이 완료되었다면 알아서 제거되었고 그렇지 않을 경우 아직 남은 타이머에 대해 제거합니다.
del_timer(&my_timer);
4. 컴파일하기
pi@raspberrypi:~/DriverStudy/day8_timer $ make
- 이전 day1 자료를 이용해서 수정하였다면 driver_init, driver_exit 함수에서 충돌 난다고 에러가 발생할 수 있습니다.
- 다른 이름으로 바꿔주면 됩니다. 예제에서는 ModuleInit, ModuleExit로 변경했습니다. 그리고 마지막 부분에 모듈이 적재될 때 호출하는 함수이름 부분에서도 수정을 해주어야 합니다.
- 정상적으로 컴파일할 경우 드라이버 파일이 생성됩니다.
5. 동작확인
- 드라이버 파일을 커널에 추가하면 타이머가 시작됩니다. 예제에서는 4초로 설정했기 때문에 대략 4초 뒤에 LED가 꺼지는 것을 확인할 수 있습니다.
pi@raspberrypi:~/DriverStudy/day8_timer $ sudo insmod day8_timer.ko
- 완료 후 모듈 제거
pi@raspberrypi:~/DriverStudy/day8_timer $ sudo rmmod day8_timer.ko
[TIP] VIM에서 화면 분할 기능
: split ./Makefile
- 화면 간 커서 이동은 Ctrl + W 후에 원하는 창으로 화살표키 (예, 위, 아래 화살표를 누르면 커서 이동)
감사합니다.
<참고 사이트>
1. Let's code a Linux Driver - 8: Timer in a Linux Kernel Module
https://www.youtube.com/watch?v=3JTfweWGjBg&list=PLCGpd0Do5-I3b5TtyqeF1UdyD4C-S-dMa&index=9
2. Raspberry Pi Pinout
3. [Linux Kernel] 시간과 타이머
4. [라즈베리파이] 커널 타이머(Kernel Timer) - jiffies란
http://egloos.zum.com/rousalome/v/9979958
5. How To Use VIM Split Screen
https://linuxhint.com/how-to-use-vim-split-screen/
6. Linux 커널에서의 디바이스 드라이버 작성
https://www.joinc.co.kr/w/Site/Embedded/Documents/WritingDeviceDriversInLinux
7. ezgif.com