디바이스 트리 디버깅 기법
디바이스 트리 문제 해결을 위해 필수 도구를 활용하는 방법을 설명합니다. 다음 명령어들은 개발 과정에서 빈번히 사용됩니다:
| 명령어 | 기능 | 사용 예시 |
|---|---|---|
| dtc -I dtb -O dts | DTB를 DTS로 변환 | dtc -I dtb -O dts system.dtb > extracted.dts |
| fdtdump | DTB 구조 분석 | fdtdump --scan system.dtb |
| /proc/device-tree | 런타임 노드 확인 | cat /proc/device-tree/model |
실시간 디버깅을 위한 핵심 전략:
# 디바이스 트리 문법 검증
dtc -I dts -o /dev/null device-config.dts
# 커널 로그에서 매칭 정보 추출
dmesg | grep "of_match"
# 동적 드라이버 바인딩 테스트
echo "example,custom-gpio" > /sys/bus/platform/drivers/gpio-driver/new_id
# 핀 제어 설정 확인
find /proc/device-tree/pinctrl -name "*gpio*" -exec cat {} \;
실습: 사용자 정의 GPIO 디바이스 구현
다음 예제는 두 개의 입력 버튼과 단일 LED를 제어하는 디바이스를 구현합니다. 핀 구성은 다음과 같이 정의됩니다:
// gpio-control.dts
/dts-v1/;
/ {
compatible = "example,custom-board";
fragment@0 {
target = <&pinctrl>;
__overlay__ {
gpio_ctrl: gpio_ctrl {
pins = "PB5", "PB6", "PB7";
function = "gpio";
drive-strength = <8>;
};
};
};
fragment@1 {
target-path = "/";
__overlay__ {
custom_gpio {
compatible = "example,simple-gpio";
status = "okay";
pinctrl-0 = <&gpio_ctrl>;
led = <&pio 1 5 GPIO_ACTIVE_LOW>; // PB5
btn_primary = <&pio 1 6 GPIO_ACTIVE_HIGH>; // PB6
btn_secondary = <&pio 1 7 GPIO_ACTIVE_HIGH>; // PB7
};
};
};
};
드라이버 코드는 인터럽트 기반 제어 로직을 구현합니다:
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
struct gpio_ctrl {
struct gpio_desc *led;
struct gpio_desc *btns[2];
int irq_primary;
int irq_secondary;
};
static irqreturn_t btn_handler(int irq, void *data)
{
struct gpio_ctrl *ctx = data;
bool primary_pressed = (irq == ctx->irq_primary) ||
gpiod_get_value(ctx->btns[0]);
gpiod_set_value(ctx->led, primary_pressed);
return IRQ_HANDLED;
}
static int gpio_probe(struct platform_device *pdev)
{
struct gpio_ctrl *ctx;
int ret;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx) return -ENOMEM;
ctx->led = devm_gpiod_get(&pdev->dev, "led", GPIOD_OUT_LOW);
ctx->btns[0] = devm_gpiod_get(&pdev->dev, "btn_primary", GPIOD_IN);
ctx->btns[1] = devm_gpiod_get(&pdev->dev, "btn_secondary", GPIOD_IN);
ctx->irq_primary = gpiod_to_irq(ctx->btns[0]);
ret = devm_request_irq(&pdev->dev, ctx->irq_primary,
btn_handler, IRQF_TRIGGER_RISING,
"primary_btn", ctx);
platform_set_drvdata(pdev, ctx);
return 0;
}
static const struct of_device_id gpio_match[] = {
{ .compatible = "example,simple-gpio" },
{ }
};
static struct platform_driver gpio_driver = {
.probe = gpio_probe,
.driver = {
.name = "gpio-controller",
.of_match_table = gpio_match,
},
};
module_platform_driver(gpio_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("사용자 정의 GPIO 제어 드라이버");
디바이스 트리 설계 가이드라인
잘못된 디바이스 트리 정의로 인한 커널 부팅 실패를 방지하기 위해 반드시 확인해야 할 사항:
// 오류 사례: 필수 속성 누락
sensor@40000000 {
compatible = "example,temperature";
// 주소 매핑 정보 누락!
};
// 올바른 정의
sensor@40000000 {
compatible = "example,temperature";
reg = <0x40000000 0x1000>;
interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <1000000>;
};
핵심 검증 포인트:
- 모든 메모리 매핑 디바이스에
reg속성 필수 포함 - 인터럽트 사용 디바이스는
interrupts및interrupt-parent정의 - 동적 핀 제어가 필요한 경우
pinctrl설정 검증 - 호환성 문자열(
compatible)은 벤더-모델 형식으로 명시