General Purpose IO

sungho·2025년 1월 1일

디바이스 드라이버

목록 보기
7/12

GPIO는 일반적인 용도의 입출력 포트로 마이크로컨트롤러나 SoC에서 외부 장치와 통신하거나 제어하는 데 사용됩니다. GPIO의 개념, 구조, 회로도 이해, 제어 방법 그리고 GPIO 디바이스 드라이버 개발까지 GPIO에 대해 설명하겠습니다.

1. GPIO 개념

  • GPIO(General Purpose Input/Output)
    • 일반적인 용도의 입출력 핀
    • 사용자가 소프트웨어를 통해 입/출력 방향, 신호 레벨 등을 설정하여 다양한 용도로 활용
    • LED, 스위치, 센서, 모터 등 다양한 외부 장치를 제어하거나 외부 장치로부터 신호를 입력받는 데 사용
  • SoC의 입출력 핀
    • CPU, GPU, 메모리 컨트롤러, 주변 장치 컨트롤러 등이 통합된 칩
    • GPIO 핀을 통해 외부 장치와 통신하고 제어
  • GPIO + Alternate Functions
    • 기본적으로 입/출력 기능을 제공하지만 대체 기능(Alternate Functions)을 통해 다른 용도로 사용
    • 특정 GPIO 핀은 UART, SPI, I2C, PWM 등의 통신 인터페이스로 사용
  • GPIO 핀의 수
    • BCM2711은 58개의 GPIO 핀을 제공
    • 여러 Bank로 그룹화
      • Bank
        • GPIO 핀들을 묶어서 관리하는 논리적인 단위
      • Bank 0
        • GPIOs 0 to 27
      • Bank 1
        • GPIOs 28 to 45
      • Bank 2
        • GPIOs 46 to 57

2. GPIO 구조와 회로 이해

GPIO 구조

  • Pin Direction Regs
    • GPIO 핀의 입/출력 방향을 설정하는 레지스터
    • 레지스터의 비트 값을 변경하여 특정 핀을 입력 또는 출력으로 설정
    • 특정 핀을 출력으로 설정하려면 해당 비트를 1로 입력으로 설정하려면 0으로 설정
  • Pull Up Control Regs, Pull Up State
    • GPIO 핀의 내부 풀업 저항을 활성화/비활성화하는 레지스터
    • 풀업 저항은 입력 핀의 상태가 불확실(floating)할 때 핀을 High 레벨로 유지하는 역할
    • 풀업 저항을 활성화하면 핀이 High 상태를 유지하며 신호가 Low로 변경될 때를 감지
  • Pull Dn Control Regs, Pull Dn State
    • GPIO 핀의 내부 풀다운 저항을 활성화/비활성화하는 레지스터
    • 풀다운 저항은 입력 핀의 상태가 불확실(floating)할 때 핀을 Low 레벨로 유지하는 역할
    • 풀다운 저항을 활성화하면 핀이 Low 상태를 유지하며 신호가 High로 변경될 때를 감지
  • Function Select Regs
    • GPIO 핀의 기능을 선택하는 레지스터
    • 핀은 여러 대체 기능을 가질 수 있으며 이 레지스터를 통해 어떤 기능을 사용할지 선택
    • 특정 핀을 UART TX로 사용하려면 해당 핀에 대한 Function Select Regs의 비트를 UART TX 기능에 맞게 설정
  • Pin Set & Clear Regs
    • GPIO 핀의 출력 상태를 High 또는 Low로 설정하는 레지스터입니다.
    • Pin Set 레지스터에 1을 쓰면 해당 핀의 출력이 High가 되고 Pin Clear 레지스터에 1을 쓰면 Low가 됩니다.
  • Output State
    • GPIO 핀의 현재 출력 상태를 나타냄
  • Low Level Detect Enable Regs, High Level Detect Enable Regs
    • GPIO 핀의 입력 신호 레벨을 감지하여 인터럽트를 발생시키는 기능을 활성화/비활성화하는 레지스터
    • 특정 핀의 입력 신호가 Low 레벨일 때 인터럽트를 발생시키려면 해당 핀에 대한 Low Level Detect Enable Regs의 비트를 1로 설정
  • Level Detect
    • GPIO 핀의 현재 입력 신호 레벨을 나타냄
    • 레지스터를 읽어 현재 핀의 입력 상태를 확인
  • Rising Edge Detect Enable Regs, Falling Edge Detect Enable Regs
    • GPIO 핀의 입력 신호 에지(Rising 또는 Falling)를 감지하여 인터럽트를 발생시키는 기능을 활성화/비활성화하는 레지스터
    • Rising Edge는 신호가 Low에서 High로 변하는 것을 의미
    • Falling Edge는 High에서 Low로 변하는 것을 의미
  • Async Rising Edge Detect Enable Regs, Async Falling Edge Detect Enable Regs
    • GPIO 핀의 입력 신호 에지를 비동기적으로 감지하여 인터럽트를 발생시키는 기능을 활성화/비활성화하는 레지스터
    • 동기적 에지 감지는 시스템 클럭에 맞춰 에지를 감지
    • 비동기적 에지 감지는 클럭과 무관하게 에지를 감지
  • Event Detect Status Regs
    • GPIO 핀에서 발생한 이벤트(레벨 변화, 에지 감지 등)를 나타내는 레지스터
    • 인터럽트가 발생했을 때 이 레지스터를 확인하여 어떤 이벤트가 발생했는지 파악
  • Interrupts
    • GPIO 핀에서 발생한 이벤트에 대한 인터럽트 신호
    • CPU는 GPIO 핀의 상태 변화를 감지하고 적절한 동작을 수행
  • Pin Level Regs
    • GPIO 핀의 현재 입력 신호 레벨을 저장하는 레지스터
    • 레지스터는 값을 직접 저장하며 Level Detect는 실시간 상태를 나타냄

신호 흐름

  1. GPIO 핀을 입력으로 설정
    • Function Select Regs를 통해 해당 핀을 GPIO 기능으로 설정
    • Pin Direction Regs를 통해 입력 방향으로 설정
    • 필요에 따라 Pull Up Control Regs 또는 Pull Dn Control Regs를 통해 내부 풀업/풀다운 저항을 활성화
  2. GPIO 핀의 입력 값 읽기
    • 외부 장치에서 GPIO 핀으로 신호를 입력
    • 입력된 신호 레벨은 Level Detect를 통해 감지
    • Pin Level Regs 또는 Level Detect 레지스터를 읽어 GPIO 핀의 현재 입력 값을 확인
  3. GPIO 핀의 입력 변화에 따른 인터럽트 발생
    • Low Level Detect Enable Regs, High Level Detect Enable Regs, Rising Edge Detect Enable Regs, Falling Edge Detect Enable Regs 등을 통해 특정 조건에서의 인터럽트 발생을 활성화
    • 설정된 조건이 만족되면 Event Detect Status Regs에 해당 이벤트가 기록되고 Interrupts 신호가 발생
    • CPU는 인터럽트 신호를 감지하고 인터럽트 핸들러를 실행
    • 인터럽트 핸들러는 Event Detect Status Regs를 확인하여 어떤 이벤트가 발생했는지 파악하고 적절한 동작을 수행
  4. GPIO 핀을 출력으로 설정
    • Function Select Regs를 통해 해당 핀을 GPIO 기능으로 설정
    • Pin Direction Regs를 통해 출력 방향으로 설정
  5. GPIO 핀의 출력 값 설정
    • SW 엔지니어는 Pin Set & Clear Regs를 사용하여 GPIO 핀의 출력 값을 High 또는 Low로 설정
    • 설정된 출력 값은 Output State에 반영

레지스터 상호작용

  • GPIO17 핀을 출력을 high로 설정하고 rising edge 인터럽트를 활성화
    1. Function Select Regs(GPIO17은 GPFSEL1에 속함)
      • GPIO17 핀을 GPIO 기능으로 설정
    2. Pin Direction Regs(GPIO17은 GPFSEL1에 속함)
      • GPIO17 핀을 출력으로 설정
    3. Pin Set & Clear Regs
      • GPIO17 핀의 출력을 High로 설정
    4. Rising Edge Detect Enable Regs
      • GPIO17 핀의 Rising Edge 감지 인터럽트를 활성화

회로도/핀 설정/배치 이해



  • HW 엔지니어의 역할
    • 하드웨어 엔지니어는 시스템 설계 과정에서 GPIO 핀의 용도를 결정하고, 회로도, 핀 설정, 부품 배치도를 작성하여 소프트웨어 개발자에게 제공
    • 회로도
      • GPIO 핀이 어떤 외부 장치와 연결되는지 그리고 어떻게 회로가 구성되는지를 보여주는 도면
    • 핀 설정
      • GPIO 핀의 기능, 입/출력 방향, 풀업/풀다운 저항 설정 등을 정의
    • 부품 배치도
      • PCB(Printed Circuit Board) 상에서 부품의 물리적 위치를 나타내는 도면
  • SW 엔지니어의 역할
    • HW 엔지니어가 제공한 회로도, 핀 설정, 부품 배치도를 참고하여 GPIO 드라이버를 개발
    • Function Select Regs를 통해 핀의 기능을 설정
    • Pin Direction Regs를 통해 입/출력 방향을 설정하고 필요에 따라 Pull Up/Dn Control Regs를 설정
    • Pin Set & Clear Regs를 통해 출력값을 제어하고 Pin Level Regs를 통해 입력값을 리딩
    • 인터럽트가 필요한 경우 관련 레지스터(Rising Edge Detect Enable Regs 등)을 설정하고 인터럽트 핸들러를 작성
  • GPIO 핀 할당
    • GPIO2 핀은 SDA(I2C 데이터), GPCLK2(General Purpose Clock 2) 등의 기능을 수행
    • GPIO 핀의 기능은 Function Select Regs 레지스터를 통해 설정
  • Register View
    • BCM2711 SoC에서 GPIO 관련 레지스터들은 0xFE200000 주소부터 할당
    • 레지스터는 32비트 크기이며 특정 기능을 제어하는 데 사용
    • GPFSEL0 레지스터는 GPIO 0~9 핀의 기능을 설정하는 데 사용

라즈베리파이4 GPIO 핀 다이어그램

  • 라즈베리파이 4는 40핀 GPIO 헤더를 제공
  • 3번 핀은 GPIO2(SDA)로 사용될 수 있고 5번 핀은 GPIO3(SCL)로 사용

3. GPIO 제어 방법

1. sysfs를 통한 GPIO 제어

  • 개념
    • sysfs는 리눅스 커널의 디바이스 모델을 사용자 공간에 노출하는 가상 파일 시스템
    • sysfs를 통해 GPIO를 제어하는 것은 가장 일반적이고 이식성이 좋은 방법
    • GPIO는 이미 리눅스 커널의 디바이스 드라이버 프레임워크에 포함되어 있어 별도의 드라이버 개발 없이 sysfs를 통해 GPIO를 사용
    • /sys/class/gpio 디렉터리를 통해 GPIO를 제어
  • 형태
    • /sys/class/gpio/export
      • GPIO 핀을 사용자 공간에 노출하는 데 사용
    • /sys/class/gpio/unexport
      • GPIO 핀을 사용자 공간에서 해제하는 데 사용
    • /sys/class/gpio/gpioN/(N은 GPIO 핀 번호)
      • direction
        • GPIO 핀의 입/출력 방향을 설정(in/out)
      • value
        • GPIO 핀의 입력 값을 읽거나 출력 값을 설정(0/1)
      • edge
        • GPIO 핀의 인터럽트 발생 조건을 설정(none/rising/falling/both)
      • active_low
        • GPIO 핀의 활성 상태를 반전(0/1)
  • 방법
    • Shell에서 설정
      1. export

        • /sys/class/gpio/export 파일에 GPIO 핀 번호를 쓰면 해당 핀이 사용자 공간에 노출
        echo 17 > /sys/class/gpio/export
      2. direction

        • /sys/class/gpio/gpioN/direction 파일에 "in" 또는 "out"을 써서 입/출력 방향을 설정
        echo out > /sys/class/gpio/gpio17/direction
      3. value

        • /sys/class/gpio/gpioN/value 파일에 0 또는 1을 써서 출력 값을 설정하거나, 파일 내용을 읽어 입력 값을 확인
        # GPIO17 핀을 High로 설정
        echo 1 > /sys/class/gpio/gpio17/value
        
        # GPIO17 핀의 입력 값 확인
        cat /sys/class/gpio/gpio17/value
      4. LED 확인

        • GPIO17에 연결된 LED가 켜지거나 꺼지는 것을 확인
      5. unexport

        • /sys/class/gpio/unexport 파일에 GPIO 핀 번호를 쓰면 해당 핀이 사용자 공간에서 해제
        echo 17 > /sys/class/gpio/unexport

2. Memory-mapped I/O를 통한 GPIO 제어

  • 개념
    • 메모리 주소에 직접 접근하여 I/O 장치를 제어
    • GPIO 레지스터는 특정 메모리 주소에 매핑
    • devmem 유틸리티를 사용하여 특정 메모리 주소의 값을 읽거나 쓰기
  • 실험을 위한 devmem 활용
    • devmem은 사용자 공간에서 직접 메모리 주소에 접근할 수 있는 유틸리티
    • GPIO 레지스터를 직접 조작하여 GPIO 핀을 제어하는 데 사용
    • devmem을 통해 GPIO를 제어하는 것은 실험적인 방법이며 시스템 안정성에 위험을 초래
  • 기본 커널 설정 변경
    • devmem을 사용하려면 커널 설정에서 CONFIG_STRICT_DEVMEM 옵션을 비활성화
    • 보안을 위해 /dev/mem 장치에 대한 접근을 제한하는 역할
    • 커널 cmdline에 mem=2G strict-devmem=0를 추가하여 부팅 시 적용
  • 리눅스 Shell에서 VA(Virtual Address) 사용
    • devmem은 가상 주소를 사용
  • GPIO 핀 기능 설정 (GPFSEL0)
    • devmem을 사용하여 GPFSEL0 레지스터(GPIO 0~9 핀의 기능 설정)의 값을 읽고 쓰기
    • GPIO17 핀의 기능을 확인하려면 GPFSEL1 레지스터(주소: 0xFE200004)의 23:21 비트를 확인
      # GPIO17 핀의 기능 확인 (GPFSEL1 레지스터의 23:21 비트)
      devmem 0xFE200004
      
      # 출력 예시: 0x00024000
      # 23:21 비트가 000 이므로 GPIO17은 입력 모드로 설정
    • GPIO17 핀을 출력 모드로 설정하려면 GPFSEL1 레지스터의 23:21 비트를 001로 설정
      # GPIO17 핀을 출력 모드로 설정 (GPFSEL1 레지스터의 23:21 비트를 001로 설정)
      devmem 0xFE200004 32 0x00024000 # 0000 0000 0000 0000 0010 0100 0000 0000
  • GPIO 핀 출력 값 설정 (GPSET0, GPCLR0)
    • GPSET0 레지스터(주소: 0xFE20001C)
      • GPIO 핀을 High로 설정하는 데 사용
    • GPCLR0 레지스터(주소: 0xFE200028)
      • GPIO 핀을 Low로 설정하는 데 사용
    • GPIO17 핀을 High로 설정하려면 GPSET0 레지스터의 17번 비트를 1로 설정
      # GPIO17 핀을 High로 설정 (GPSET0 레지스터의 17번 비트를 1로 설정)
      devmem 0xFE20001C 32 0x00020000 # 0000 0000 0000 0010 0000 0000 0000 0000
    • GPIO17 핀을 Low로 설정하려면 GPCLR0 레지스터의 17번 비트를 1로 설정
      # GPIO17 핀을 Low로 설정 (GPCLR0 레지스터의 17번 비트를 1로 설정)
      devmem 0xFE200028 32 0x00020000 # 0000 0000 0000 0010 0000 0000 0000 000

3. GPIO 디바이스 드라이버

  • 개념
    • GPIO를 제어하기 위한 커널 드라이버를 작성하는 것이 가장 안정적이고 권장되는 방법
    • gpio_로 시작하는 API를 사용하여 GPIO 핀을 제어
  • API
    • gpio_request(unsigned gpio, const char *label)
      • GPIO 핀을 사용하기 위해 커널에 요청
        • gpio
          • 사용할 GPIO 핀 번호
        • label
          • GPIO 핀을 식별하기 위한 레이블
    • gpio_free(unsigned gpio)
      • 사용이 끝난 GPIO 핀을 해제
    • gpio_direction_input(unsigned gpio)
      • GPIO 핀을 입력 모드로 설정
    • gpio_direction_output(unsigned gpio, int value)
      • GPIO 핀을 출력 모드로 설정하고, 초기 출력 값을 value로 설정
    • gpio_set_value(unsigned gpio, int value)
      • GPIO 핀의 출력 값을 설정
    • gpio_get_value(unsigned gpio)
      • GPIO 핀의 입력 값 리딩
    • gpio_set_value_cansleep(unsigned gpio, int value)
      • gpio_set_value()와 유사하지만, sleep이 허용되는 컨텍스트에서 사용
    • gpio_get_value_cansleep(unsigned gpio)
      • gpio_get_value()와 유사하지만, sleep이 허용되는 컨텍스트에서 사용
  • 코드
    // 모듈 파라미터로 GPIO 핀 번호와 출력 값을 설정
    #define KDT_GPIO_OUTPUT 17
    #define KDT_GPIO_INPUT 16
    
    static ssize_t kdt_driver_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
    {
        // copy_to_user() 함수의 반환값을 0과 비교하여 복사 성공 여부 확인
        char data[2];
        data[0] = (char) gpio_get_value(KDT_GPIO_INPUT) + '0';
        data[1] = '\0';
        if (copy_to_user(buf, data, 1)) { // GPIO 핀 값을 읽어와서 사용자 공간으로 복사
            pr_err("Failed to copy data to user space\n");
            return -EFAULT; // 에러 발생 시 -EFAULT 반환
        }
        pr_info("Value of button: %d\n", gpio_get_value(KDT_GPIO_INPUT)); // GPIO 핀 값 읽기
        return 1; // 복사한 바이트 수 반환
    }
    
    static ssize_t kdt_driver_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset)
    {
        // copy_from_user() 함수의 반환값을 0과 비교하여 복사 성공 여부 확인
        char kernel_write_buffer[BUF_SIZE];
        if (copy_from_user(kernel_write_buffer, buf, len)) {
            pr_err("Failed to copy data from user space\n");
            return -EFAULT; // 에러 발생 시 -EFAULT 반환
        }
        kernel_write_buffer[len] = '\0';
        
        
        switch (kernel_write_buffer[0])
        {
            case '0':
                pr_info("low\n");
                gpio_set_value(KDT_GPIO_OUTPUT, 0); // GPIO 핀 값을 0으로 설정
                break;
            case '1':
                pr_info("high\n");
                gpio_set_value(KDT_GPIO_OUTPUT, 1); // GPIO 핀 값을 1로 설정
                break;
            default:
                pr_info("Invalid Input!\n");
                break;
        }
    
        pr_info("write: done\n");
        return len; // 복사한 바이트 수 반환
    }
    
    static int __init kdt_module_init(void)
    {
        /* 여기서 노드를 할당 받는다. */
        if (alloc_chrdev_region(&kdt_dev, 0, 1, DRIVER_NAME) < 0) {
            pr_err("Device Nr. could not be allocated!\n");
            return -1;
        }
        pr_info("Allocated Major = %d & Minor = %d \n", MAJOR(kdt_dev), MINOR(kdt_dev));
    
        /* device class 생성 */
        if ((kdt_class = class_create(THIS_MODULE, DRIVER_CLASS)) == NULL) {
            pr_err("Device class can not be created!\n");
            goto ClassError;
        }
    
        /* device file 생성 */
        if (device_create(kdt_class, NULL, kdt_dev, NULL, DRIVER_NAME) == NULL) {
            pr_err("Can not create device file!\n");
            goto FileError;
        }
    
        /* character device file 초기화 */
        cdev_init(&kdt_cdev, &fops);
    
        /* 커널에 등록 */
        if (cdev_add(&kdt_cdev, kdt_dev, 1) == -1) {
            pr_err("Registering of device to kernel failed!\n");
            goto AddError;
        }
        
        // GPIO 핀 요청
        if (gpio_request(KDT_GPIO_OUTPUT, "kdt-gpio-17")) {
            pr_err("Can not allocate GPIO 17\n");
            goto GpioOutError;
        }
    
        // GPIO 핀을 출력으로 설정
        if (gpio_direction_output(KDT_GPIO_OUTPUT, 0)) {
            pr_err("Can not set GPIO 17 to output!\n");
            goto GpioOutDirError;
        }
        
        // GPIO 핀 요청
        if (gpio_request(KDT_GPIO_INPUT, "kdt-gpio-16")) {
            pr_err("Can not allocate GPIO 16\n");
            goto GpioInError;
        }
    
        // GPIO 핀을 입력으로 설정
        if (gpio_direction_input(KDT_GPIO_INPUT)) {
            pr_err("Can not set GPIO 16 to input!\n");
            goto GpioInDirError;
        }
        
        pr_info("kdt_gpio_driver loaded\n");
        return 0;
        
    GpioInDirError:
        gpio_free(KDT_GPIO_INPUT);
        pr_err("Failed to set GPIO 16 to input!\n");
    GpioInError:
        gpio_free(KDT_GPIO_OUTPUT);
        pr_err("Can not allocate GPIO 16\n");
    GpioOutDirError:
        gpio_free(KDT_GPIO_OUTPUT);
        pr_err("Can not set GPIO 17 to output!\n");
    GpioOutError:
        cdev_del(&kdt_cdev);
        pr_err("Can not allocate GPIO 17\n");
    AddError:
        device_destroy(kdt_class, kdt_dev);
        pr_err("Registering of device to kernel failed!\n");
    FileError:
        class_destroy(kdt_class);
        pr_err("Can not create device file!\n");
    ClassError:
        unregister_chrdev_region(kdt_dev, 1);
        pr_err("Device class can not be created!\n");
        return -1;
    }
    
    static void __exit kdt_module_exit(void)
    {
        gpio_set_value(KDT_GPIO_OUTPUT, 0); // 모듈 언로드 시 GPIO 핀을 0으로 설정
        gpio_free(KDT_GPIO_OUTPUT); // GPIO 핀 사용 해제
        gpio_free(KDT_GPIO_INPUT);
        cdev_del(&kdt_cdev);
        device_destroy(kdt_class, kdt_dev);
        class_destroy(kdt_class);
        unregister_chrdev_region(kdt_dev, 1);
        pr_info("kdt_gpio_driver unloaded\n");
    }
    • GPIO 핀의 입력 값을 사용자 공간으로 전달
    • 사용자 공간에서 전달받은 값에 따라 GPIO 핀의 출력 값을 설정
    • 모듈 초기화 시 GPIO 핀을 요청하고 입/출력 방향을 설정
      • gpio_request() 함수를 사용하여 GPIO 핀을 요청
      • gpio_direction_output() 함수를 사용하여 GPIO 핀을 출력으로 설정
      • gpio_direction_input() 함수를 사용하여 GPIO 핀을 입력으로 설정
      • 에러 처리
        • 단계에서 발생할 수 있는 에러를 적절히 처리
          • gpio_request() 함수가 실패하면 에러 메시지를 출력하고 이미 할당된 자원을 해제한 후 -1을 반환
    • kdt_module_exit() 함수는 모듈 종료 시 GPIO 핀을 해제
      • gpio_set_value() 함수를 사용하여 GPIO핀을 안전한 상태(Low)로 설정
      • gpio_free() 함수를 사용하여 GPIO 핀 사용을 해제
  • 유저 레벨 애플리케이션
    #include <stdio.h>#include <stdlib.h>#include <fcntl.h>#include <unistd.h>#include <string.h>#define MODULE_FILENAME "/dev/kdt_gpio_driver"int main(int argc, char *argv[])
    {
        int dev;
        char buf = (argc > 1) ? atoi(argv[1]) : 1;
    
        dev = open(MODULE_FILENAME, O_RDWR | O_NDELAY);
        if (dev < 0) {
            printf("module open error\n");
            exit(1);
        }
    
        if (write(dev, &buf, 1) < 0) {
            printf("write error\n");
            goto err;
        }
    
        if (read(dev, &buf, 1) < 0) {
            printf("read error\n");
            goto err;
        }
    
        printf("read data: %c\n", buf);
    
    err:
        close(dev);
        return 0;
    }
    • /dev/kdt_gpio_driver 장치 파일을 열고 write() 함수를 사용하여 GPIO 핀의 출력 값을 설정하고 read() 함수를 사용하여 GPIO 핀의 입력 값 리딩

4. 핀 설정 확인

  • Debugfs
    • 커널 디버깅 정보를 사용자 공간에 제공하는 가상 파일 시스템
    • /sys/kernel/debug 디렉터리에 마운트
  • pinctrl
    • 핀 컨트롤러는 SoC 내부의 핀 멀티플렉싱을 관리하는 서브시스템
    • pinctrl 디버깅 정보를 통해 핀의 현재 설정 상태를 확인
    • pinctrl-handles
      • 시스템에 등록된 pinctrl 핸들의 목록과 상태 정보를 제공
    • pinctrl-maps
      • pinctrl 드라이버가 로드한 핀 맵핑 정보를 제공
      • 핀의 기능, 풀업/풀다운 설정, 드라이브 세기 등을 확인
    • pinmux-pins
      • 핀의 현재 multiplexing 설정 상태
      • 핀의 기능, 입/출력 방향, 풀업/풀다운 설정 등을 확인
  • 확인 방법
    1. Debugfs 마운트

      sudo mount -t debugfs none /sys/kernel/debug
    2. pinctrl 정보 확인

      cat /sys/kernel/debug/pinctrl/pinctrl-handles
      cat /sys/kernel/debug/pinctrl/pinctrl-maps
      cat /sys/kernel/debug/pinctrl/fe200000.gpio/pinmux-pins # BCM2711의 GPIO 핀 정보
    • cat /sys/kernel/debug/pinctrl/fe200000.gpio/pinmux-pins 출력
      Pinmux settings per pin
      Format: pin (name): (config)
      pin 0 (GPIO0):  (MUX UNCLAIMED) (GPIO UNCLAIMED)
      pin 1 (GPIO1):  (MUX UNCLAIMED) (GPIO UNCLAIMED)
      pin 2 (GPIO2):  gpio_in (GPIO UNCLAIMED)
      pin 3 (GPIO3):  gpio_in (GPIO UNCLAIMED)
      pin 4 (GPIO4):  gpio_in (GPIO UNCLAIMED)
      pin 5 (GPIO5):  gpio_in (GPIO UNCLAIMED)
      pin 6 (GPIO6):  gpio_in (GPIO UNCLAIMED)
      ...
      pin 17 (GPIO17):  gpio_out (GPIO UNCLAIMED)
      ...
    • GPIO17 핀은 gpio_out으로 설정되어 있으며 핀이 출력 모드로 설정된 GPIO 핀

4. 결론

GPIO의 개념, 구조, 회로도 이해, 제어 방법 그리고 핀 설정 확인 방법까지 GPIO 전반에 대해 다루었습니다. GPIO는 SoC에서 외부 장치와 통신하고 제어하는데 필수적인 요소이며 리눅스 커널은 GPIO를 효율적으로 관리하기 위한 다양한 인터페이스와 프레임워크를 제공합니다.

0개의 댓글