Linux/Kernel Driver

USART Driver 작성 및 Linux Kernel에서의 USART 인터페이스 사용 방법

임베디드 친구 2025. 3. 22. 10:10
728x90
반응형

USART Driver 작성 및 Linux Kernel에서의 USART 인터페이스 사용 방법

개요

USART(Universal Synchronous/Asynchronous Receiver-Transmitter)는 임베디드 시스템에서 중요한 직렬 통신 인터페이스입니다. 이번 포스팅에서는 Rockchip RK3399 플랫폼을 기준으로, Linux Kernel에서 USART 드라이버를 작성하고, 이를 통해 데이터를 읽고 쓰는 방법을 알아보겠습니다.


USART란?

USART는 직렬 통신을 지원하는 하드웨어 모듈로, 동기 및 비동기 통신을 모두 지원합니다. 동기 통신은 별도의 클럭 신호를 사용하며, 비동기 통신은 스타트와 스톱 비트를 활용합니다. USART는 주로 센서, 디버깅, 데이터 로깅 등의 목적으로 사용됩니다.

주요 특징

  • 양방향 통신 지원
  • 동기 및 비동기 모드 지원
  • 속도와 안정성이 중요한 애플리케이션에서 활용

Linux Kernel에서 USART 드라이버 작성

Linux Kernel에서는 USART 인터페이스를 위한 다양한 드라이버를 제공합니다. RK3399 플랫폼에서 USART 드라이버를 작성하는 과정은 크게 세 단계로 나눌 수 있습니다:

  1. Device Tree 설정
  2. USART 드라이버 코드 작성
  3. read/write 인터페이스 구현

1. Device Tree 설정

USART 하드웨어를 Linux에서 사용하려면 먼저 디바이스 트리를 설정해야 합니다. RK3399의 USART 인터페이스를 설정하는 예는 다음과 같습니다.

&uart2 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&uart2_pins>;
    current-speed = <115200>;
};

2. USART 드라이버 코드 작성

USART 드라이버는 platform_driver를 사용하여 작성합니다. 기본적인 드라이버 등록 코드는 다음과 같습니다.

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>

#define DRIVER_NAME "rk3399_usart"

struct rk_usart {
    struct uart_port port;
};

static int rk_usart_probe(struct platform_device *pdev) {
    struct rk_usart *usart;

    usart = devm_kzalloc(&pdev->dev, sizeof(*usart), GFP_KERNEL);
    if (!usart)
        return -ENOMEM;

    dev_info(&pdev->dev, "USART driver probed\n");

    // USART 초기화 코드 작성

    return 0;
}

static int rk_usart_remove(struct platform_device *pdev) {
    dev_info(&pdev->dev, "USART driver removed\n");
    return 0;
}

static const struct of_device_id rk_usart_of_match[] = {
    { .compatible = "rockchip,rk3399-uart" },
    {},
};
MODULE_DEVICE_TABLE(of, rk_usart_of_match);

static struct platform_driver rk_usart_driver = {
    .driver = {
        .name = DRIVER_NAME,
        .of_match_table = rk_usart_of_match,
    },
    .probe = rk_usart_probe,
    .remove = rk_usart_remove,
};

module_platform_driver(rk_usart_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("RK3399 USART Driver");

3. read/write 인터페이스 구현

드라이버가 등록되면 데이터를 읽고 쓰기 위한 인터페이스를 구현해야 합니다. Linux UART 드라이버 프레임워크는 이를 위해 tty 계층을 제공합니다. 간단한 구현 예는 다음과 같습니다.

static int rk_usart_write(struct uart_port *port, const char *data, size_t len) {
    for (size_t i = 0; i < len; i++) {
        while (!(readl(port->membase + UART_LSR) & UART_LSR_THRE))
            cpu_relax();

        writel(data[i], port->membase + UART_TX);
    }

    return len;
}

static int rk_usart_read(struct uart_port *port, char *buf, size_t len) {
    size_t count = 0;

    while (count < len) {
        while (!(readl(port->membase + UART_LSR) & UART_LSR_DR))
            cpu_relax();

        buf[count++] = readl(port->membase + UART_RX);
    }

    return count;
}

테스트 방법

드라이버를 테스트하려면 다음 단계를 따라야 합니다:

  1. Device Tree 적용
  2. dtc -I dts -O dtb -o rk3399.dtb rk3399.dts cp rk3399.dtb /boot/dtb/
  3. 모듈 빌드 및 로드
  4. make modules insmod rk3399_usart.ko
  5. USART 동작 확인
  6. echo "Hello USART" > /dev/ttyS2 cat /dev/ttyS2

결론

이번 포스팅에서는 RK3399 플랫폼에서 USART 드라이버를 작성하고 데이터를 읽고 쓰는 방법을 알아보았습니다. 실제 애플리케이션에서 이 코드를 활용하여 다양한 시리얼 통신 기반 솔루션을 구현할 수 있습니다. 추가적으로 DMA를 활용한 데이터 전송이나 고급 에러 핸들링 기법을 학습하여 더 강력한 USART 드라이버를 개발해 보세요.


참고 자료

반응형