12주차 기록을 작성하다보니 내용이 길어져 부득이하게 나누었습니다.
12주차 -1 을 먼저 읽고 오면 내용 이해가 더 잘 될 수 있으니 링크를 걸어 놓도록 하겠습니다.

그러면 다시 12주차 기록 슈~~웃 토!

플랫폼 드라이버

등장 배경

대부분의 임베디드 SoC에는 USB나 PCI처럼 스스로 “나 여기 있어요!”라고 외칠 수 있는 장치(discoverable device)가 거의 없습니다.

대신 GPIO, UART, I²C 컨트롤러, PWM 등은 CPU 내부에 하드 와이어드(hard-wired) 되어 있어서 부팅할 때 누가 어디에 있는지 미리 알려줘야 합니다.

그래서 리눅스 커널은 이런 장치들을 위한 가상 버스를 만들었는데, 그게 바로 platform bus입니다.

platform_device     ←── 이름으로 매칭 ───→     platform_driver
(하드웨어 정보)                                   (제어 코드)
       ↑                                             ↑
       └────────────── platform bus (중개) ───────────┘

platform bus가 하는 일

binding

디바이스 트리에 기술된 하드웨어 정보와 커널에 작성된 드라이버 코드를 하나로 묶어주는 과정

Matching

  • 하드웨어 측 (DTS): compatible = "vendor,model"; 이라는 식별자를 가짐
  • 소프트웨어 측 (Driver): struct of_device_id 테이블에 자신이 지원하는 compatible 리스트 보유

바인딩은 커널이 부팅되거나 모듈이 로드될 때 플랫폼 버스(Platform Bus) 위에서 일어난다.

전체 Process

  1. 등록 (Registration)

    커널이 디바이스 트리를 읽어 platform_device를 생성하고, 드라이버가 로드 → platform_driver가 등록됩니다.

  2. 비교 (Matching)

    플랫폼 버스가 양쪽의 compatible 문자열 비교

    1. discoverable devices
    	plug -play 
    	usb, pci , - adapter interrupt!  -> enumeration ! <- device descriptor
    2. non- discoverable devices

    4가지 방법 존재

    1. OF style match → 요즘 많이 사용하는 비교 방식
      -> compatible 속성 : 문자열 비교
      -> 문자열 일치 시 probe 함수 호출
    2. the id table match → old fashion
    3. driver name match
    4. ACPI style match
  3. 결합 (Binding)

    이름이 일치하면 커널은 드라이버의 probe() 함수를 호출

  4. 전달 (Resource Passing)

    이때 디바이스 트리에 적힌 reg(주소), interrupts(번호) 등의 자원 정보가 드라이버에 전달됩니다.


Device Tree

배경

과거에는 보드마다 소스코드에 하드 코딩하거나 별도의 헤더파일을 만들어서 빌드했습니다.
→ 매번 커널을 다시 컴파일해야 했고, 유지보수가 힘들었다.
→ 이를 해결

바이너리 형태(.dtb)로 메모리에 올려두고,
커널이 부팅하면서 그 정보를 읽어서 장치를 만듭니다.

Bootloader (U-Boot, Raspberry Pi firmware 등)
       ↓
kernel8.img + .dtb 파일을 메모리에 올림
       ↓
커널 시작 → early boot 단계에서 .dtb를 읽음
       ↓
내부적으로 트리 구조로 펼쳐서 메모리에 저장
(런타임 FDT)

platform_driver의 .of_match_table과 매칭되면서 probe() 함수가 호출되는 시작점⭐️⭐️

compatible = "raspberrypi,bcm2835-gpio";

dtoverlay의 동작 방식

  1. dtoverlay my-overlay 명령 실행
  2. /boot/overlays/my-overlay.dtbo 파일 읽음
  3. 이미 메모리에 펼쳐져 있는 현재 FDT (Flattened Device Tree)를 대상으로 오버레이에 적힌 내용대로 기존 노드 수정 & 새 노드 추가
    example)
  • &i2c1 { status = "okay"; ... } → 기존 i2c1 노드 찾아서 status 변경
  • my-sensor@48 { ... } → 새로운 자식 노드 추가
  1. 변경된 내용을 커널의 of_overlay 프레임워크가 적용
  2. 변경된 부분에 해당하는 platform_device들이 새로 생성/갱신됨
  3. → 해당 compatible을 가진 드라이버의 probe() 함수가 새로 호출됨

==>💡동적 로딩 !시스템이 켜져있는 상태에서도 dtoverlay 명령어를 통해서 하드웨어 설정을 즉시 반영할 수 있다

⚠️작성 규칙 : 반드시 /dts-v1/;/plugin/; 선언이 포함되어야함

.dts 파일 변환

# dtc -@ -I dts -O dtb -o 01_dev.dtbo 01_dev.dts
01_dev.dts:16.30-24.16: Warning (unit_address_vs_reg): 
/fragment@0/__overlay__/rpihat_device@0: node has a unit name, but no reg property
#====> dts 파일을 커널이 읽을 수 있는 dtbo로 변경 

플랫폼 드라이버 패턴 (LED + KEY 실습)

static int my_probe(struct platform_device *pdev)
{
    struct my_private_data *priv;

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

    // 가장 많이 쓰는 devm_ 패밀리
    priv->led = devm_gpiod_get(&pdev->dev, "led", GPIOD_OUT_LOW);
    priv->key = devm_gpiod_get(&pdev->dev, "key", GPIOD_IN);

    priv->irq = gpiod_to_irq(priv->key);
    devm_request_irq(&pdev->dev, priv->irq, my_isr,
                     IRQF_TRIGGER_FALLING, "my-key", priv);

    platform_set_drvdata(pdev, priv);
    return 0;
}

static const struct of_device_id my_of_match[] = {
    { .compatible = "mycompany,super-hat" },
    { }
};
MODULE_DEVICE_TABLE(of, my_of_match);

static struct platform_driver my_driver = {
    .probe  = my_probe,
    .remove = my_remove,
    .driver = {
        .name = "super-hat",
        .of_match_table = my_of_match,
    }
};
module_platform_driver(my_driver);

⚠️ 주의 사항

  • devm_ 함수를 적극 활용 → remove에서 해제 안 해도 됨
  • probe 실패 시 반드시 적절한 error code 반환 (-ENODEV, -ENOMEM 등)
  • dtoverlay 먼저 → insmod 순서 지키기
  • dmesg에 디버깅용 dev_info() 적극 활용
  • compatible 문자열은 절대 오타 내지 않기 (가장 중요)

여러 드라이버

MISC

character 디바이스 드라이버 중 하나
major 번호로 장치의 종류를 구분하는 문자 장치의 구분에서 10으로 지정 된다 → 부번호만 설정하면 자동으로 장치 파일을 만들어 준다 .

  • . miscdevice의 장점
    1. 자동화: class_create, device_create를 호출하지 않아도 /dev/ 아래에 파일이 자동으로 생성
    2. Major 번호 절약: 여러 드라이버가 Major 10번을 공유하므로 커널의 리소스를 효율적으로 씁니다.
    3. 간결함: cdev_init, cdev_add 같은 복잡한 초기화 과정이 필요 없습니다.

입력 드라이버

주요 입력 장치 : 키보드 , 마우스 , 조이스틱 , 터치 스크린 등등


특징: 간헐적 데이터 발생 
			바이트 단위 데이터 
			
			인터럽트 기반의 동작 
				-> irq line

USB 
	usb keyboard 
	인터럽트 (x) -> irq 라인이 없음 [ 하드웨어 선 x ] 
		컨트롤 , 이소 , 벌크 , 인터럽트 (흉내) 전송 모드 (O)
	
	event oriented 

→ 표준화를 통해 input 디바이스 드라이버 탄생

이벤트 핸들러 디바이스 드라이버

하드웨어 ──→ 입력 장치 드라이버 (input_dev 등록)
                        ↓
               input core (이벤트 큐 관리)
                        ↓
      ┌───────────┬───────────┬───────────┐
      │           │           │           │
  evdev     keyboard   mouse     joydev   ...   ← 이벤트 핸들러들
      │           │           │           │
      ↓           ↓           ↓           ↓
   /dev/input/eventX   /dev/input/mice   콘솔 키보드 등

이벤트 핸들러는 입력 장치 드라이버(input device driver)가 생성한 이벤트를 받아서 사용자 공간(user-space)으로 전달하는 중간 역할을 하는 모듈

udev

입력 장치(키보드, 버튼, 조이스틱 등)를 만들 때마다
/dev/input/event0, /dev/input/event1, /dev/input/event2… 이런 식으로
번호가 계속 바뀌는 문제

→ 이를 어떻게 해결할 것인가 ??
udev : 동적 장치 관리자 → user system에서 동작

커널의 sysfs 과 연동하여 장치 파일을 동적으로 생성하고 관리

→ 드라이버가 인식한 장치를 사용자 친화적인 환경으로 만들어 주는 사용자 공간의 관리자

  • 기능
    • 장치 인식: 새로운 장치 파일 연결시 커널로부터 정보를 받아 인식
    • 장치 파일 생성 : /dev 디렉터리에 적절한 장치 파일 생성
    • 규칙 기반 관리 : /etc/udev/rules.d 에 정의된 규칙 파일과 비교

구현 예시

root@rpi:/etc/udev/rules.d# cat 99-rpihat.rules
SUBSYSTEM=="input", KERNEL=="event*", ATTRS{name}=="rpihat",
 SYMLINK+="input/rpihat", MODE="0666"
 # 파일 생성 

숫자가 클 수록 나중에 적용된다 → 99 설정

# 1. 규칙 새로고침
sudo udevadm control --reload-rules
root@rpi:~/exercise_A05.251102/08# systemctl restart udev
# 2. 이미 꽂혀있는 장치들에게 규칙 강제 적용 (또는 드라이버를 rmmod -> insmod 해도 됨)
sudo udevadm trigger

root@rpi:~# ls -l /dev/input/rpihat
lrwxrwxrwx 1 root root 6  18 11:37 /dev/input/rpihat -> event2
=> 확인 가능 

I2C 이해하기

I²C(Inter-Integrated Circuit)는 2선만으로 여러 장치를 연결할 수 있는 직렬 통신 프로토콜입니다.

구성 요소

  • SDA : 데이터가 실제로 오가는 선 (양방향)
  • SCL : 마스터가 만드는 클럭(박자) 선
  • Pull-up 저항 (필수❗) : 신호가 없을 때 High 상태 유지

마스터-슬레이브 구조

마스터(Raspberry Pi)가 클럭을 만들고, 슬레이브(센서, OLED 등)가 대답합니다.

  • Start : SCL High + SDA High → Low
  • Stop : SCL High + SDA Low → High

트랜잭션 (주소 + 레지스터 + 데이터 1바이트)

Start
   │
   ▼
SCL  ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐
     │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
  ┌──┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘
SDA  A6 A5 A4 A3 A2 A1 A0 W  (7bit 주소 + W=0)   ACK   D7~D0   ACK   Stop
     └───────────────────────┘                 └────────┘
       Master가 보냄           Slave가 ACK      Master 데이터   Slave ACK1

Start → [7bit 주소 + W(0)] → ACK → [레지스터 주소] → ACK → [데이터] → ACK → Stop
→ 9번째 비트마다 ACK(NACK) 확인이 들어갑니다.

특징

  • 선이 2개라 회로가 단순하고 127개 까지 장치를 붙일 수 있음
  • SPI에 비해 속도가 느리고 풀업 저항 설정이 중요함(노이즈에 취약)
  1. 가장 먼저 해보는 I²C 디버깅 3단계 (꼭 해보세요!)
    새로운 I²C 장치를 붙였을 때 무조건 이 순서로 확인합니다.

Linux에서의 I2C 통신 전체 Flow

전체 FLOWModule to Excute
i2c_adapter        ← 하드웨어 (BCM2835 I²C 컨트롤러) → /dev/i2c-1
     ↑
i2c_algorithm      ← 전송 방법 (master_xfer 함수 포인터): 소프트웨어 측면
     ↑
i2c_client         ← 우리가 만드는 드라이버 (BMP280, SSD1306 등)

Soc에는 대개 I2C 컨트롤러가 내장되어 있음 → 저수준 인터페이스

→ 이게 /dev/i2c-{num} → 이렇게 장치 파일로 표현됨

해당 디바이스 파일을 열고 write , read, ioctl 함수를 호출하면 각각 i2c adapter의 함수로 연결

❔ioctl : I2C 버스는 여러 장치가 공유하므로, "지금 누구랑 말할 것인가"를 결정

→ 사용자 공간에서는 /dev/i2c-1 파일을 열고 ioctl(I2C_SLAVE)로 “지금 누구랑 얘기할지” 정합니다.

I2C Adapter

Adapter의 종류

i2cdetect -F <busaddress. ie, 1> 
1. I2C 
	standard 
2. SMBus   ( is a subset of I2C ) 
	variation (-> PC , notebook)
	
	smbus_ * => 비교적 안전하게 쓸 수 있음 

표준 I2C Adapter를 활용한 값 읽기 및 설정

#장치가 버스에 붙었는지 확인
i2cdetect -y 1→ 0x76 (BMP280), 0x3C (SSD1306) 등이 보이면 성공

#칩 ID 읽어보기 (가장 확실한 생존 확인)
i2cget -y 1 0x76 0xD0 b   # BMP280 → 0x58 나와야 정상

#레지스터 직접 쓰고 읽기 (기본 통신 확인)
i2cset -y 1 0x76 0xE0 0xB6   # 소프트 리셋
i2cget -y 1 0x76 0xD0 b

사용자 공간에서 I²C 직접 제어하는 실습

BMP280 칩 ID 읽기 예제 : 0xD0 값 읽어 오기

  • src code

       #include <sys/ioctl.h>
       #include <linux/i2c-dev.h>
       
       #define I2C_BUS_PATH        "/dev/i2c-1" // RPi의 기본 I2C 버스
       #define BMP280_I2C_ADDR     0x76         // 센서의 슬레이브 주소
       #define BMP280_ID_REG       0xD0         // 칩 ID가 저장된 레지스터 주소
       
       int main() {
           int fd;
           unsigned char buf[1];
       
           // 1. I2C 버스 파일 열기
           fd = open(I2C_BUS_PATH, O_RDWR);
           // 2. 통신할 대상(Slave) 주소 설정
           if (ioctl(fd, I2C_SLAVE, BMP280_I2C_ADDR) < 0) {
     		.
           }
           // 3. 읽고 싶은 레지스터 번호를 먼저 전송 (Write)
           // "지금부터 0xD0번지에 있는 값을 알고 싶어"라고 명령하는 단계
           buf[0] = BMP280_ID_REG;
           write(fd, buf, 1);
           // 4. 레지스터 값 읽기 (Read)
           // 센서가 보낸 1바이트 데이터를 수신
           read(fd, buf, 1) ;
    
           // 5. 결과 출력 (BMP280의 경우 정상 시 0x58 출력)
           printf("BMP280 Chip ID: 0x%02X\n", buf[0]);
       
           close(fd);
       }

커널 I²C 클라이언트 드라이버 패턴 (BMP280)

기본 패턴

static int bmp280_probe(struct i2c_client *client) {
    // 1. 장치가 맞는지 ID 확인
    u8 id;
    i2c_smbus_read_byte_data(client, 0xD0);  // 0x58 확인

    // 2. private data 할당
    struct bmp280_data *data = devm_kzalloc(...);

    // 3. i2c device 등록
    i2c_set_clientdata(client, data);

    // 4. sysfs나 character device 생성 (선택)
    return 0;
}

static const struct i2c_device_id bmp280_id[] = {
    { "bmp280", 0 },
    { }
};

static struct i2c_driver bmp280_driver = {
    .driver = { .name = "bmp280" },
    .probe = bmp280_probe,
    .id_table = bmp280_id,
};
module_i2c_driver(bmp280_driver);

SMBus

리눅스는 원래 PC 친화적.

SMBus(Smart Battery Bus, I²C의 서브셋)를 기본적으로 더 잘 지원합니다.

SMBus 장점

  • 타임아웃 기능 → 장치가 멈추면 버스 초기화
  • PEC(Packet Error Checking) → 데이터 신뢰성 향상

모든 리눅스 I²C 어댑터가 SMBus 명령을 보장

→ 그래서 실습에 사용한 BMP280 이외에도 대부분의 센서는 i2c_smbus_read_byte_data() 같은 함수를 씁니다.

BMP280을 활용한 클라이언트 드라이버의 구현은 BMP280 Driver 에 구현 내용을 따로 정리하도록 하겠습니다!

IIO(Industrial I/O)

산업용 센서 및 I/O장치를 위한 표준화 프레임 워크

탄생 배경

  • 파편화된 드라이버 => 각 센서마다 독자적인 드라이버 및 인터페이스 필요
    • application 개발자가 매번 새로운 인터페이스를 학습 해야함
  • 비효율적인 데이터 처리
  • 복잡한 드라이버 개발

해결책

- 통합된 API 
- 고성능 데이터 처리
			버퍼링
- 재사용 가능한 프레임 워크

구성

  • IIO Core
    • 드라이버 등록 및 관리
    • 드라이버와 사용자 공간을 연결하는 역할
    • 특징
      • 드라이버 개발자는 IIO 코어 API를 사용해 자신의 장치를 쉽게 등록
      • CORE에서 복잡한 것을 처리
  • IIO channel
    • 센서의 개별 측정 항목을 나타내는 논리적인 단위
      • 각 채널은 고유한 속성을 가짐 ⇒ 센서 각각의 정보 (ie, x,y,z,정보 )
      • 속성들은 sysfs를 통해 사용자 공간에 노출
  • IIO Buffer
    • 센서 데이터 일시 저장 FIFO 버퍼
    • 데이터 효율화 → 오버헤드 감소 (샘플을 모아서 전달 )
    • 동기화
  • IIO Trigger
    • 데이터 샘플링을 쓰거나 버퍼에 데잍를 써놓도록 하는 이벤트
    • 특징
      • iio_device_enable_buffer() 함수를 통해 트리거와 버퍼를 연결 후 다양한 트리거 소스 사용

Flow example

[물리 세계]
     ↓   (물리량 → 전기 신호)
센서 (BMP280, DHT11, MPU6050 등)

     ↓   (아날로그 → 디지털, 레지스터 읽기)
드라이버 (IIO 드라이버 코드)

     ↓   (측정값 → 채널별 raw/processed 값)
IIO 채널 (in_temp_raw, in_pressure_input 등)

     ↓   (트리거 발생 시점에 데이터 캡처)
트리거 (timer / external GPIO / software)

     ↓   (캡처된 데이터 임시 저장)
IIO 버퍼 (FIFO처럼 쌓아두기)

     ↓   (IIO core가 관리)
IIO Core (sysfs + /dev/iio:deviceX 인터페이스 제공)

     ↓   (두 가지 주요 경로)
├─── A. sysfs 경로 ──→ 설정/단일 값 읽기
│                         (/sys/bus/iio/devices/iio:deviceX/in_*)
└─── B. 문자 장치 파일 ──→ 고속/연속 데이터 스트리밍
                              (/dev/iio:deviceX read())

     ↓
사용자 공간 애플리케이션
(libiio, 직접 read(), cat, iio_info 등)

IIO VS sysfs VS Character device

sysfs

장점 : 간편한 key -value 쌍으로 설정 및 접근 ⇒ 구현이 간단 

단점 
- read : 한번에 한개의 샘플 데이터만 읽음 → 데이터 스트리밍에 부적합
- 타이밍이 보장되지 않음
- 버퍼링 및 큐잉 기능 없음

Device file 방식

open , read , write ,  ioctl을 통한 접근 

장점 : 자유도가 높다 . ioctl로 복잡한 제어 명령 설정 가능 

단점 	

- 장치마다 제각각인 명령 형식 → 호환성 x
- read, open ,write 등 모든 인터페이스를 직접 구현해야하는 부담

IIO 접근방식

- 표준화된 인터페이스 제공
	- sysfs를 통해 장치 설정 및 정보 조회
    
- 통합된 버퍼링 방식 제공
	- dev/iio:deviceX  형태의 문자 장치 파일을 사용할 수 있음 .
    - read() 함수를 통해 버퍼링된 데이터 묶음을 효율적으로 읽을 수 있다
    
	    → 비동기적 read 
    
- trigger 지원
- 다채널 지원 → 온도 압력 습도 등을 하나의  버퍼에 동시에 받는다

IIO 사용 예제

DHT-11를 활용하여 라즈베리 파이에서 IIO 실습을 진행했습니다.

#IIO 코어 모듈 로드 
root@rpi:~/# modprobe industrialio

#dht-11 module 확인 
root@rpi:~/# modprobe -D dht11
insmod /lib/modules/6.1.21-v8+/kernel/drivers/iio/industrialio.ko.xz 
insmod /lib/modules/6.1.21-v8+/kernel/drivers/iio/humidity/dht11.ko.xz 

# 의존성을 가진다 
root@rpi:~/# lsmod | grep 03_dev
03_dev                 16384  0
industrialio           90112  2 iio_hwmon,03_dev
-> industrialio 먼저 올려야함 

root@rpi:~/# modinfo 03_dev.ko
filename:       /root/../03_dev.ko
license:        GPL v2
description:    DHT11 humidity/temperature sensor driver
srcversion:     C1D68BD9D145141E3DCFD8E
alias:          of:N*T*CrpihatC*
alias:          of:N*T*Crpihat
depends:        industrialio
name:           03_dev
vermagic:       6.1.21-v8+ SMP preempt mod_unload modversions aarch64

=========================================================
#모듈 로드 이후 
root@rpi:/sys/bus/iio/devices/iio:device0# xxd in_temp_input 
00000000: 3235 3032 0a                             2502.
root@rpi:/sys/bus/iio/devices/iio:device0# xxd in_humidityrelative_input 
00000000: 3138 3030 0a                             1800.
root@rpi:/sys/bus/iio/devices/iio:device0 
=> 해당 경로에 인터페이스 생성  
==> APP client에서도 여기서 값을 읽어온다.
  • src code
    static const struct iio_chan_spec dht11_chan_spec[] = {    
    	{ 
    		.type = IIO_TEMP ,        
    		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 
    	},            
    	{ 
    		.type = IIO_HUMIDITYRELATIVE,        
    		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), 
    	}
    };
    iio = devm_iio_device_alloc(dev, sizeof(*dht11));
    dht11 = iio_priv(iio);  // iio->priv → dht11 구조체 연결
    
    iio->name = pdev->name;
    iio->info = &dht11_iio_info;              // read_raw() 콜백 연결
    iio->modes = INDIO_DIRECT_MODE;          // 버퍼링 모드 지정 
    iio->channels = dht11_chan_spec;          // 온도/습도 2개 채널
    iio->num_channels = ARRAY_SIZE(dht11_chan_spec);
    
    devm_iio_device_register(dev, iio);       // IIO 디바이스 등록 (/sys/bus/iio/ 아래 생성)
    IIO 등록 → in_temp_input, in_humidityrelative_input 자동 생성
    • 인터럽트 + 타이머 중심 동작은 misc device기반 드라이버 구현과 동일
  • result
    root@rpi:~/# ./app
    Temperature: 2507
    
    Humidity is: 1700
    
    ================= > 클라이언트에서 값을 확인 후 출력 
  • IIO VS Misc Device
항목Misc DeviceIIO 버전차이점
인터페이스/dev/rpihat (misc device) + cat으로 문자열 출력/sys/bus/iio/devices/iio:deviceX/ (sysfs) + /dev/iio:deviceX (버퍼링)표준화 (IIO) vs 커스텀 (misc)
데이터 접근 방식read() → 단일 값 (습도 온도 문자열)read_raw()온도/습도 각각 독립 채널로 정수 값 제공채널별 분리 + 고속 버퍼링 가능
사용자 접근 방법cat /dev/rpihat → "550 2500"cat /sys/bus/iio/.../in_temp_input → 온도
cat/sys/bus/iio/.../in_humidityrelative_input → 습도
IIO 표준 경로 사용 (다른 IIO 센서와 동일)
버퍼링/스트리밍없음 (1회 읽기)/dev/iio:deviceX read로 버퍼링된 샘플 묶음 읽기 가능고속/연속 측정에 최적화
트리거/비동기 지원없음IIO trigger (timer/external) 사용 가능 → 주기적 자동 샘플링실시간 스트리밍 가능
호환성/확장성낮음 (커스텀 인터페이스)높음 (IIO는 libiio, ROS, Yocto 등에서 표준 지원)현대 리눅스 센서 표준

해당 내용을 마지막으로 12주차의 내용이 끝났습니다 . 다양한 디바이스별로 여러 드라이버 구현 방법을 빠르게 배우면서 코드 구현 보다는 차이점 파악 및 다뤄보기 위주로 교육이 흘러갔는데요 . . 앞으로 혼자서 끄적여 보면서 실제로 디바이스 드라이버를 만드는 임베디드 초고수가 되기 위해서 달려 나가 보겠습니닷

🏃🏃🏃🏃

리눅스 디바이스 드라이버 끄읏~~~!!

12주차 자투리

월요일에 점심 근처 카페에서 커피를 샀더니 꽃까지 받아 부러씁니다.
괜시리 꽃을 보고 기분이 좋아지는 것은 1살을 더 먹었기 때문일까요 .. 헛헛 😭

Welcome to my World .
Just Enjoy your life
And Good Luck .

profile
세상의 어려운 문제를 해결하자

0개의 댓글