ARM_core 기반 리눅스 BSP 개발/Raspberry_PI Kernel build

[Raspberry_PI]_Kernel Thread-Based LED Blinking in Linux

juniha 2025. 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" 로그 등 확인

구현 영상