[Raspberry_PI]_Kernel Thread-Based LED Blinking in Linux
juniha2025. 6. 25. 18:27
목적
Linux kernel thread 를 활용하여 사용자 개입 없이 주기적으로 LED를 점멸시키는 기능을 구현함으로써, kernel 수준에서의 병행 처리 및 하드웨어 제어 기법을 이해하고, GPIO 인터페이스와 커널 스레드의 동작 원리를 확인.
환경
Raspberrypi 3B, 64bit, 6.12, y-ssh로 접속
구현 과정
Mobaxterm 에서 ssh pi@192.168.0.36 접속
mkdir ~/c_project // 홈 디렉토리에 'c_project'라는 새 디렉토리 생성
mkdir ~/c_project/led_blink // 'c_project' 디렉토리 안에 'led_blink'라는 하위 디렉토리 생성
cd ~/c_project/led_blink // 'led_blink' 디렉토리로 이동
코드 작성
nano led_blink.c // nano 편집기로 'led_blink.c' 파일을 생성하거나 열기
Makefile 생성
nano Makefile // nano 편집기로 'Makefile'을 생성(또는 열어) 편집
Makefile 코드
obj-m += led_blink.o // led_blink.c를 컴파일하여 커널 모듈로 만들기 위한 오브젝트 파일 지정
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
// 현재 커널 버전의 빌드 디렉토리에서 현재 디렉토리(M) 기준으로 모듈 빌드 수행
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
// 모듈 빌드 시 생성된 중간 파일 및 결과물 정리
LED_Blink 코드
#include <linux/module.h> // 커널 모듈 작성에 필요한 헤더
#include <linux/gpio/consumer.h> // GPIO 컨슈머 API를 위한 헤더
#include <linux/delay.h> // 지연 함수(msleep 등)를 위한 헤더
#include <linux/kthread.h> // 커널 스레드 관련 헤더
#include <linux/sched.h> // 스케줄링 관련 헤더
// GPIO 디스크립터를 위한 포인터 선언
static struct gpio_desc *led;
// 사용할 GPIO 번호 및 오프셋 정의 (플랫폼 의존)
#define GPIO_LED 17
#define GPIO_OFFSET 512
// 커널 스레드 객체 선언
static struct task_struct *blink_thread;
// 스레드로 실행될 함수 - LED를 주기적으로 점멸
static int blink_func(void *data) {
while(!kthread_should_stop()) { // 스레드 종료 요청 전까지 반복
gpiod_set_value(led, 1); // LED ON
msleep(500); // 500ms 대기
gpiod_set_value(led, 0); // LED OFF
msleep(500); // 500ms 대기
}
return 0;
}
// 모듈이 insmod 될 때 실행되는 함수
static int __init led_blink_init(void) {
printk(KERN_INFO "LED Blink module init\n");
// GPIO 디스크립터 얻기 (GPIO 번호 + 오프셋)
led = gpio_to_desc(GPIO_LED + GPIO_OFFSET);
if(!led) {
printk(KERN_ERR "Error getting pin info 17\n");
return -ENODEV; // 디바이스 없음 에러 반환
}
// GPIO를 출력 모드로 설정 (초기값: 0)
int status = gpiod_direction_output(led, 0);
if(status) {
printk(KERN_ERR "Error setting pin 17 to output\n");
return status;
}
// LED 점멸 스레드 생성
blink_thread = kthread_run(blink_func, NULL, "LED Blink");
if(IS_ERR(blink_thread)) {
printk(KERN_ERR "Error creating thread\n");
return PTR_ERR(blink_thread); // 에러 코드 반환
}
return 0;
}
// 모듈이 rmmod 될 때 실행되는 함수
static void __exit led_blink_exit(void) {
printk(KERN_INFO "LED blink module exit\n");
if(blink_thread)
kthread_stop(blink_thread); // 스레드 중지 요청
gpiod_set_value(led, 0); // LED OFF
}
// 모듈 초기화 및 종료 함수 등록
module_init(led_blink_init);
module_exit(led_blink_exit);
// 모듈 라이선스 명시 (GPL 필수)
MODULE_LICENSE("GPL");
라이브러리 설치
sudo apt-get update
// 패키지 목록을 최신 상태로 갱신
sudo apt-get upgrade
// 설치된 패키지를 최신 버전으로 업그레이드
sudo apt-get install -y build-essential raspberrypi-kernel-headers
// 필수 빌드 도구와 Raspberry Pi용 커널 헤더 설치 (-y 옵션은 자동으로 'yes' 선택)
make 실행 후
lsmod // 현재 커널에 적재된(로드된) 모듈들의 목록 출력
sudo insmod led_blink.ko // 컴파일된 led_blink 커널 모듈을 커널에 적재 (LED 점멸 시작)
lsmod // led_blink 모듈이 정상적으로 적재되었는지 다시 확인
dmesg // 커널 메시지를 확인 (모듈 적재 로그 또는 에러 메시지 확인)
// "LED Blink module init" 등의 로그 확인 가능
// --- LED가 약 0.5초 간격으로 깜빡이는지 물리적으로 확인 ---
sudo rmmod led_blink // 커널에서 led_blink 모듈 제거 (LED 점멸 종료)
lsmod // 모듈이 정상적으로 제거되었는지 확인
dmesg // 커널 메시지에서 "LED blink module exit" 로그 등 확인