이 블로그는 임베디드 컴퓨터를 이용한 장치(시스템) 개발과 원격제어에 필요한 지식을 공유 하기 위한 블로그 입니다.
실제 개발과 프로그램 예를 위하여 Microchip 사의 ATmega128를 사용한 보드와 Arduino Mega 보드(ATmega2560), Raspberry Pi Pico, Raspberry Pi, WiFi 모듈을 사용 합니다.

python-gpio-interrupt

Raspberry Pi Pico GPIO Port와 Interrupt - MicroPython
Raspberry Pi Pico GPIO Port와 Interrupt - MicroPython


  • Raspberry Pi Pico GPIO Port
    • 일반적인 GPIO Port의 이해에 도움이 되는 참고자료: "ATmega128 I/O Port"

    • RP2040 GPIO Port
      • Pi Pico GPIO Port의 논리적 구조(Logical structure)

      • Raspberry Pi Pico는 RP2040 마이크로 컨트롤러에서 사용할 수 있는 User bank(GPIO0 to GPIO29)의 핀 가운데 Raspberry Pi Pico 보드 핀에 연결된 26개(GP0 - GP22 까지와 GP26, GP27, GP28번)의 핀을 사용할 수 있다. GP23, GP24, GP25, GP29 핀은 Pi Pico 보드의 핀에 연결되지 않았기 때문에 사용할 수 없다.
      • GP22를 제외한 다른 GPIO 핀은 프로그램 설정으로 미리 설정된 다른 목적(PIO, SPI, UART, I2C, ADC, PWM, GPCLK)으로 사용할 수 있다. 그러나 동시에 다른 기능으로 설정할 수는 없다.
      • GPIO 핀의 외부 Interrupt 기능을 설정할 수 있다.
      • 각 GPIO의 CTRL 레지스터에 있는 FUNCSEL 필드에 기능(Function) 코드를 Writing 하면 해당 기능(Function)이 설정된다.
      • 참고자료: "RP2040 Datasheet"의 "2.19.2. Function Select"를 참고 바람.

      • 각 GPIO는 한 번에 하나의 기능을 선택할 수 있다. 각 주변 장치 입력(예: UART0 RX)은 한 번에 하나의 GPIO만 선택해야 한다.
    • GPIO Pads
    • Pad는 칩의 내부 로직과 외부 회로 사이의 전기적 인터페이스(electrical interface)이다.

      GPIO의 IO pad(1개) Diagram

      • 각 GPIO는 "Pad"를 통해 칩 외부에 연결된다.
      • Pad는 신호의 전압 레벨을 변환하고 더 높은 전류를 지원하며 정전기 방전(ESD) 이벤트에 대한 보호 기능을 제공한다.
      • Pad의 전기적 기능은 외부 회로의 요구 사항을 충족하도록 조정할 수 있다.
        • 출력 구동 전류의 강도를(2mA, 4mA, 8mA 또는 12mA) 설정할 수 있다.
        • 출력 슬루율(slew rate)을 느리게 또는 빠르게 설정할 수 있다.
        • 입력 히스테리시스(Schmitt trigger mode드) 기능 활성화가 가능하다.
        • 풀업 또는 풀다운(Pull-up or Pull-down)을 활성화하여 출력 드라이버가 활성화되지 않은 경우 출력 신호 레벨을 설정할 수 있다.
        • Pad가 사용되지 않거나 연결되지 않았거나 아날로그 신호에 연결된 경우 전류 소비를 줄이기 위해 입력 버퍼를 비 활성화할 수 있다.

    • GPIO Interrupts
      • 각 GPIO 핀은 아래와 같이 4종류의 외부 Interrupt를 생성할 수 있다.
        • Level high(Logical 1)
        • Level Low(Logical 0)
        • Positive edge( Transition from active low to active high)
        • Negative edge( Transition from active high to active low)
      • 레벨 인터럽트(Level interrupts)는 래치되지 않는다. 만약 핀이 Logical 1 이고 Level high 인터럽트가 활성화된 경우 핀이 Logical 0로 변경되는 순간 비활성화된다.
      • 에지 인터럽트(Edge interrupts)는 자동으로 INTR 레지스터(Rg)에 저장된다. INTR 레지스터에 저장된 Edge interrupts 상태는 해당 Interrupt 가 실행되거나 INTR 레지스터에 Writing operation을 실행하면 Cleare 된다.
      • 세 가지 인터럽트 대상(proc 0, proc 1,dormant_wake)에 각각 enable, status, force 레지스터가 있다. proc 0의 경우 Enable Rg(PROC0_INTE0), Status Rg(PROC0_INTS0), Force Rg(PROC0_INTF0) 가 있다.
      • 휴면 깨우기(Dormant wake)는 ROSC 또는 XOSC를 휴면 모드에서 깨우는 데 사용된다.

    • GPIO에 사용하는 레지스터(Registers)
    • GPIO에 사용하는 Rg는 기술적인 내용을 포함하고 종류가 많기 때문에 각 Rg에 대한 설명은 생략한다. 그러나 GPIO에 사용하는 Rg 이름과 상수는 프로그램 과정에서 필요하기 때문에 참고자료를 첨부한다.

      참고자료: "RP2040 Datasheet"의 "2.19.6. List of Registers"를 참고 바람.

        일반적인 이용자는 아래 레지스터(Registers) 요약 설명은 생략하여도 된다.

      • GPIO에 사용하는 레지스터(Registers) 요약
        • User Bank IO Rg: User Bank IO Rg는 기본 주소 0x40014000(SDK에서 IO_BANK0_BASE로 정의됨)에서 시작한다.

        • IO_BANK0: GPIOi_STATUS
        • GPIO0_STATUS - GPIO29_STATUS를 저장하는 Rg(위에서 i는 0 . . . 29)

        • IO_BANK0: GPIOi_CTRL

          GPIO0_CTRL - GPIO29_CTRL를 저장하는 Rg(위에서 i는 0 . . . 29). GPIO의 기능 선택(Function select)과 재정의(Overrides)에 사용한다.

        • IO_BANK0: INTRi

          GPIO0_LEVEL_LOW, GPIO0_LEVEL_HIGH, GPIO0_EDGE_LOW, GPIO0_EDGE_HIGH - - - GPIO29_EDGE_HIGH

          GPIO0 - GPIO29의 Raw Interrupts 상태(위에서 i는 0, 1, 2, 3)를 저장한다. 각 GPIO의 상태를 4Bits(1 Word(32 bits)에 8개 GPIO의 Raw Interrupts를 저장하기 때문에 30개의 GPIO를 위하여 4 Word 가 필요)를 사용하여 저장한다.

        • IO_BANK0: PROC0_INTEi
        • GPIO0_LEVEL_LOW, GPIO0_LEVEL_HIGH, GPIO0_EDGE_LOW, GPIO0_EDGE_HIGH - - - GPIO7_EDGE_HIGH

          PROC0의 Interrupt Enable(위에서 i는 0, 1, 2, 3)를 설정한다. 각 GPIO에 4종류(4Bits 사용)의 Interrupt를 설정할 수 있다. 1 Word(32 bits)에 8개 Interrupt(30개의 GPIO를 위하여 4 Word 가 필요)를 설정한다.

        • IO_BANK0: PROC0_INTFi
        • GPIO0_LEVEL_LOW, GPIO0_LEVEL_HIGH, GPIO0_EDGE_LOW, GPIO0_EDGE_HIGH - - - GPIO7_EDGE_HIGH

          PROC0의 Interrupt Force(위에서 i는 0, 1, 2, 3)를 설정한다. 각 GPIO에 4종류(4Bits 사용)의 Interrupt Force를 설정할 수 있다. 1 Word(32 bits)에 8개 Interrupt Force를 설정한다.

        • IO_BANK0: PROC0_INTSi
        • GPIO0_LEVEL_LOW, GPIO0_LEVEL_HIGH, GPIO0_EDGE_LOW, GPIO0_EDGE_HIGH - - - GPIO7_EDGE_HIGH

          Masking 및 forcing 실행 후 PROC0의 Interrupt status(위에서 i는 0, 1, 2, 3). 각 GPIO의 상태는 4종류(4Bits 사용) 중 한 상태일 수 있다.

        • IO_BANK0: PROC1_INTEi
        • GPIO0_LEVEL_LOW, GPIO0_LEVEL_HIGH, GPIO0_EDGE_LOW, GPIO0_EDGE_HIGH - - - GPIO7_EDGE_HIGH

          PROC1의 Interrupt Enable(위에서 i는 0, 1, 2, 3)를 설정한다. 각 GPIO에 4종류(4Bits 사용)의 Interrupt를 설정할 수 있다. 1 Word(32 bits)에 8개 Interrupt(30개의 GPIO를 위하여 4 Word 가 필요)를 설정한다.

        • IO_BANK0: PROC1_INTFi
        • GPIO0_LEVEL_LOW, GPIO0_LEVEL_HIGH, GPIO0_EDGE_LOW, GPIO0_EDGE_HIGH - - - GPIO7_EDGE_HIGH

          PROC1의 Interrupt Force(위에서 i는 0, 1, 2, 3)를 설정한다. 각 GPIO에 4종류(4Bits 사용)의 Interrupt Force를 설정할 수 있다. 1 Word(32 bits)에 8개 Interrupt Force를 설정한다.

        • IO_BANK0: PROC1_INTSi
        • GPIO0_LEVEL_LOW, GPIO0_LEVEL_HIGH, GPIO0_EDGE_LOW, GPIO0_EDGE_HIGH - - - GPIO7_EDGE_HIGH

          Masking 및 forcing 실행 후 PROC1의 Interrupt status(위에서 i는 0, 1, 2, 3). 각 GPIO의 상태는 4종류(4Bits 사용) 중 한 상태일 수 있다.

        • DORMANT_WAKE_INTEi
        • GPIO0_LEVEL_LOW, GPIO0_LEVEL_HIGH, GPIO0_EDGE_LOW, GPIO0_EDGE_HIGH - - - GPIO7_EDGE_HIGH

          Dormant_wake의 Interrupt Enable(위에서 i는 0, 1, 2, 3)를 설정한다. 각 GPIO에 4종류(4Bits 사용)의 Interrupt를 설정할 수 있다. 1 Word(32 bits)에 8개 Interrupt(30개의 GPIO를 위하여 4 Word 가 필요)를 설정한다.

        • DORMANT_WAKE_INTFi
        • GPIO0_LEVEL_LOW, GPIO0_LEVEL_HIGH, GPIO0_EDGE_LOW, GPIO0_EDGE_HIGH - - - GPIO7_EDGE_HIGH

          Dormant_wake의 Interrupt Force(위에서 i는 0, 1, 2, 3)를 설정한다. 각 GPIO에 4종류(4Bits 사용)의 Interrupt Force를 설정할 수 있다. 1 Word(32 bits)에 8개 Interrupt Force를 설정한다.

        • DORMANT_WAKE_INTSi
        • GPIO0_LEVEL_LOW, GPIO0_LEVEL_HIGH, GPIO0_EDGE_LOW, GPIO0_EDGE_HIGH - - - GPIO7_EDGE_HIGH

          Masking 및 forcing 실행 후 Dormant_wake의 Interrupt status(위에서 i는 0, 1, 2, 3). 각 GPIO의 상태는 4종류(4Bits 사용) 중 한 상태일 수 있다.


  • MicroPython libraries(class Pin – control I/O pins)
    • Pin object(class Pin)
      • Pin 개체는 I/O Pin을 제어하는 데 사용된다. Pin 클래스에는 Pin 모드(IN, OUT 등)를 설정하는 메서드와 디지털 값을 가져오고(Input) 설정(Output)하는 메서드가 있다.

        여기에서는 자주시용하는 항목과 Methods만 요약하여 설명한다. 전체 자료는 아래 참고자료를 참고하기 바람.

      • Pin object 생성자(Constructors): class machine.Pin(id, mode=- 1, pull=- 1, *, value, drive, alt)
        • id: Pin 식별자로 필수 인수(다른 인수는 선택 사항)이다. 가능한 값 유형은 int(핀을 식별하는 정수), str(핀 이름), tuple([port, pin]) 이다.
        • mode: 핀 모드 설정 값으로 Pin.IN, Pin.OUT, Pin.OPEN_DRAIN 등으로 설정할 수 있다.
        • pull: pull up 저항의 시용여부를 설정한다. None, Pin.PULL_UP,Pin.PULL_DOWN 중 하나로 설정한다.
        • value: Pin.OUT 과 Pin.OPEN_DRAIN 모드에서만 유효하다.
        • GPIO2를 Output Pin으로 설정하는 예
        • from machine import Pin

          p2 = Pin(2, Pin.OUT)

      • Methods
        • Pin.init(mode=- 1, pull=- 1, *, value, drive, alt): 주어진 매개 변수를 사용하여 핀을 다시 초기화한다. 지정된 인수 만 설정된다. 나머지 핀 주변 장치 상태는 변경되지 않는다.
        • Pin.value([x]): 핀 값을 설정(Pin.OUT 모드)하거나 갖어(Pin.IN 모드) 오는 경우에 시용한다. 만약 인수가 샹략된 경우 핀의 디지털 값을 갖어 온다.
        • Pin.on(): 핀을 디지털 값 "1"로 설정한다.
        • Pin.off(): 핀을 디지털 값 "0"로 설정한다.
        • Pin.mode([mode]): 핀 모드를 설정하거나 갖어(인수가 없는 경우) 온다.
        • Pin.pull([pull]): 핀 상태를 설정하거나 갖어(인수가 없는 경우) 온다.
        • Pin.irq(handler=None, trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, *, priority=1, wake=None, hard=False)
          • 핀의 트리거 소스가 활성화 될 때 호출 할 인터럽트 핸들러를 구성한다. 핀 모드가 Pin.IN 이면 트리거 소스는 핀의 외부 값 이다. 핀 모드가 Pin.OUT 이면 트리거 소스는 핀의 출력 버퍼이다.

          • handler: 인터럽트가 트리거 될 때 호출되는 함수(생략될 수도 있음)이다.
          • trigger: 인터럽트가 발생하는 조건을 설정한다. 가능한 값은 Pin.IRQ_FALLING, Pin.IRQ_RISING, Pin.IRQ_LOW_LEVEL, Pin.IRQ_HIGH_LEVEL 이다. 이 값은 OR'ed 되기 때문에 하나 이상의 조건에서 인터럽트가 트리거 되게 설정할 수 있다.
          • priority: 인터럽트의 우선 순위를 설정한다. 취할 수있는 값은 포트 별로 다르지만 더 높은 값이 더 높은 우선 순위를 갖는다.
      • 핀 설정에 서용하는 상수(Constants)
        • 핀 모드를 설정하는 데 사용하는 상수: Pin.IN, Pin.OUT, Pin.OPEN_DRAIN
        • Pull up 저항을 설정하는 데 사용하는 상수: Pin.PULL_UP, Pin.PULL_DOWN, Pin.PULL_HOLD
        • 인터럽트(IRQ) 트리거 타입을 설정하는 데 사용하는 상수: Pin.IRQ_FALLING, Pin.IRQ_RISING, Pin.IRQ_LOW_LEVEL, Pin.IRQ_HIGH_LEVEL

        참고자료: MicroPython libraries(class Pin – control I/O pins)

    • Raspberry Pi Pico 보드에 내장된 LED 와 BOOTSEL Button
      • Pi Pico 보드에 내장된 LED 와 BOOTSEL Button 위치

    • 프로그램 예: Switch(Push button)와 LED
      • 이 프로그램은 Pin object를 생성하고 Method를 사용하는 가장 기본이 되는 예 이다.

        실험을 위한 회로 구성 예

        주: Raspberry Pi Pico는 GPIO25를 On-board LED 제어에 사용하고, Raspberry Pi Pico W는 WL_GPIO0(Infineon CYW43439의 GPIO0)를 On-board LED 제어에 사용한다.

        주: 위 회로에서 LED 회로(보드에 점선으로 연결)는 개발보드에 내장된 LED를 사용하기 때문에 실제 회로 구성은 하지 않아도 된다.

      • Switch(Push button)의 상태를 LED에 출력하는 프로그램 예
      • 실험 방법
        • 위 프로그램을 복사하여 File name "sw_status_led.py"로 저장 한다.
        • Thonny IDE를 실행하고 Thonny IDE의 사용 환경(Thonny 실행에 사용할 장치와 COM Port 선택)이 바르게 되어 있는지 확인한다.
        • Thonny IDE의 Python shell 창에 prompt( >>> )가 출력되었는 확인한다.
        • Thonny IDE의 "파일 -> 열기"를 실행하여 프로그램 파일(sw_status_led.py)을 Open 한다.
        • 실험
          • "실행 -> 현재 스크립트 실행"을 실행하거나 Toolbar의 "실행" Icon을 클릭하면 스크립트가 개발보드에 전송되고 프로그램이 실행된다.
          • 버튼(GPIO22 Pin을 사용함)을 누르면 LED가 On 되고 누르지 않으면 Off 상태가 된다.

  • 외부 인터럽트(External interrupt)
    • Pi Pico 보드의 GPIO Pin은 외부 신호를 받아 이 신호에 대응하는 인터럽트(External interrupt)를 발생 시키는 목적으로 사용 할 수 있다.

    • 프로그램 예: Switch Counter(Bouncing 현상 이해)
      • Switch를 누른 회수를 카운트(External interrupt를 이용)하여 콘솔창에 출력하는 프로그램 예
      • 실험 방법
        • 위 프로그램을 복사하여 File name "switch_counter_interrupt.py"로 저장 한다.
        • Thonny IDE를 실행하고 Thonny IDE의 사용 환경(Thonny 실행에 사용할 장치와 COM Port 선택)이 바르게 되어 있는지 확인한다.
        • Thonny IDE의 Python shell 창에 prompt( >>> )가 출력되었는 확인한다.
        • Thonny IDE의 "파일 -> 열기"를 실행하여 프로그램 파일(switch_counter_interrupt.py)을 Open 한다.
        • 실험
          • "실행 -> 현재 스크립트 실행"을 실행하거나 Toolbar의 "실행" Icon을 클릭하면 스크립트가 개발보드에 전송되고 프로그램이 실행된다.
          • 버튼(GPIO22 Pin을 사용함)을 누르면 콘솔창에 버튼을 누른 회수가 출력된다. 이 실험에서 버튼을 한번 눌러도 경우에 따라 카운터 값이 1 이상 증가 할 수(Bouncing 현상 때문) 있다.

        주: 스위치의 물리적인 결함 때문에 스위치를 누르거나 뗄 때 Bouncing 현상이 발생할 수 있다.

        참고자료: Switch debouncing 과 Keypad

        참고자료: 프로그램 예: SW Debouncing

      • 프로그램 예: External Interrupt(SW)를 이용한 LED 제어
        • Switch를 누르면 LED의 상태가 Toggle(현재 상태가 On 이면 Off 상태로, Off 상태인 경우는 On 상태로 됨)되는 프로그램 예
        • 실험 방법
          • 위 프로그램을 복사하여 File name "switch_toggle_led_interrupt.py"로 저장 한다.
          • Thonny IDE를 실행하고 Thonny IDE의 사용 환경(Thonny 실행에 사용할 장치와 COM Port 선택)이 바르게 되어 있는지 확인한다.
          • Thonny IDE의 Python shell 창에 prompt( >>> )가 출력되었는 확인한다.
          • Thonny IDE의 "파일 -> 열기"를 실행하여 프로그램 파일(switch_toggle_led_interrupt.py)을 Open 한다.
          • 실험
            • "실행 -> 현재 스크립트 실행"을 실행하거나 Toolbar의 "실행" Icon을 클릭하면 스크립트가 개발보드에 전송되고 프로그램이 실행된다.
            • 버튼(GPIO22 Pin을 사용함)을 누르면 LED의 상태가 Toggle 된다. 이 실험에서 버튼을 눌러도 LED의 현재 상태가 변동하지 않는 경우가 발생 할 수(Bouncing 현상 때문에 버튼을 2회 누른 것으로 인식되는 경우) 있다.

    • Raspberry Pi Pico GPIO Port와 Interrupt 관련 페이지 보기