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

pwm-pico-c

Pico PWM - C/C++ SDK
Raspberry Pi Pico PWM(Pulse width modulation) - C/C++ SDK


  • RP2040 PWM(Pulse width modulation)
    • 참고자료: "RP2040 Datasheet A microcontroller by Raspberry Pi" 4.5. PWM

    • RP2040 PWM 개요
      • PWM slice의 Block diagram

      • 16-bit Up/Down Counter
      • 주파수 측정을 위한 Edge-sensitive input mode
      • Duty cycle 측정을 위한 Level-sensitive input mode
      • 8.4 fractional clock divider
      • 2개의 독립된 출력 채널, 0%에서 100%까지 Duty cycle
      • FAST PWM Mode와 Phase Correct PWM Mode
      • Configurable counter wrap value: Wrap 과 Level Registers 이중 버퍼링되어 PWM 실행 중에 Race-free로 변경할 수 있다.
      • Interrupt 과 DMA request
      • Pin B를 Input으로 설정한 경우 PWM slice를 입력 신호의 Duty cycle 또는 Frequency 측정에 이용할 수 있다.
    • Programmer’s Model
      • PWM Channels이 사용하는 GPIO Pin
        • PWM Channels이 사용하는 GPIO Pin mapping

        • 위 표와 같이 16개의 PWM channels(8 slices x 2-channel)이 GPIO0 - GPIO15에 출력될 수 있다.
        • 또한 GPIO16 - GPIO29에 14개의 PWM channels이 중복되어 출력될 수 있다.
        • 두개의 GPIO 핀에서 동일한 PWM 출력을 선택할 수 있으며, 각 GPIO에 동일한 신호가 출력된다.
      • FAST PWM Mode
        • 16-bit Up/Down Counter와 PWM 출력 예

        • FAST PWM Mode에서 Up/Down Counter는 Up Counting mode(Top 까지 Counting한 다음 0가 됨)로 동작한다.
        • Up/Down Counter의 값은 CC(Counter compare) Rg의 값과 계속 비교된다. Up/Down Counter의 값이 CC Rg 값보다 작은 경우 GPIO에 High 가 출력되고 CC Rg 값보다 큰은 경우 GPIO에 Low 가 출력된다. High - Low 출력은 Control register의 설정에 따라 반전(Low - High)되어 출력될 수 있다.
        • 그 결과 CC Rg 값이 큰 경우 High 상태(Duty cycle)의 폭이 넓어 지고 CC Rg 값이 작 경우 High 폭이 좁아 지기 때문에 Pulse 폭은 CC Rg 값에 비례(Pulse Width Modulation)하게 된다.
        • Counting 주기는 TOP register의 값에 의하여 제어된다. TOP Rg가 16비트 이기 때문애 Top의 최대값은 65536 이 된다.
      • Phase Correct PWM Mode
        • 16-bit Up/Down Counter와 PWM 출력 예

        • Phase Correct PWM Mode에서 Up/Down Counter는 0에서 Top에 도달할 때 까지는 Up Counting을 하고, Top에 도달한 다음 0 까지 Down Counting을 한다. 그 결과 Pulse 폭 해상도는 증가하고 동작 주파수는 1/2로 감소한다.
        • 기타 동작은 FAST PWM Mode와 동일하다.
      • CC Rg의 Double Buffering
        • 만약 PWM가 동작중에 CC Rg의 값을 변경하면 출력에 원하지 않은 Pulse가 출력될 수 있기 때문에 CC Rg를 Double Buffering 하여 Up/Down Counter가 Top에서 0로 변동(Counter wraps)하는 순간에만 CC Rg의 값이 Update 된다.
      • Duty Cycle을 0% 또는 100%로 설정하기
        • Duty Cycle을 0%(Off 상태: 최소 전류) 또는 100%(최대 전류)로 설정할 때 전력 제어소자(예: MOSFET)의 손실( Switching losses)을 최소화 하기 위하여 CC Rg의 값을 아래와 같이 설정하여야 한다.

        • 0%로 설정: CC Rg의 값을 0로 설정한다.
        • 100%로 설정: CC Rg의 값을 Top + 1로 설정한다.
      • Clock Divider와 PWM Period 설정
        • Fractional clock divider 설정(DIV_INT, DIV_FRAC)에 따른 Enable signal. Enable signal이 High 인 상태에서 만 Counter 가 Count 동작을 수행한다.

        • 각 Slice에 포함되어 있는 Fractional clock divider(8 integer bit, 4 fractional bit)를 이용하여 Count rate를 최대 256배까지 늦출 수 있다.
        • DIV_INT는 Count rate를 늦추는 비율을 결정한다.
          • DIV_INT 가 1인 경우 Counter enable 신호는 계속 High 상태를 유지하여 Counter는 125 MHz system clock를 계속 Count 한다.
          • DIV_INT 가 2인 경우 Counter enable 신호는 1/2 Clock 동안만 High 상태를 유지하여 Counter는 125 MHz system clock의 1/2만 Count 한다.
          • DIV_INT 가 3인 경우 Counter enable 신호는 1/3 Clock 동안만 High 상태를 유지하여 Counter는 125 MHz system clock의 1/3만 Count 한다.
        • DIV_FRAC는 DIV_INT의 값을 DIV_INT <− (DIV_INT + DIV_FRAC/16)로 설정한 것과 같다. DIV_FRAC가 0인 경우 DIV_INT <− (DIV_INT + 0/16)이 되어 DIV_FRAC의 영향은 없다. DIV_INT가 2 이고 DIV_FRAC 가 8인 경우 (2 + 8/16) = 2.5 가 되어 Counter는 125 MHz system clock의 1/2.5만 Count 한다.
        • 위 결과 PWM 출력 신호 주파수를 대략 7.5 Hz - 125 MHz(System clock)의 넓은 범위로 설정하는 것이 가능하다.
        • PWM Free-running period
          • PWM Free-running period는 아래와 같이 TOP register,Phase-correct mode 설정(CSR_PH_CORRECT), DIV register(DIV_INT, DIV_FRAC)에 의하여 결정된다.
          • period = (TOP + 1) x (CSR_PH_CORRECT + 1) x (DIV_INT + (DIV_FRAC / 16))

          • Output frequency는 System clock frequency에 따라 아래와 같이 결정된다.
          • fpwm = fsys / period = fsys /((TOP + 1) x (CSR_PH_CORRECT + 1) x (DIV_INT + (DIV_FRAC / 16)))

      • Level-sensitive 과 Edge-sensitive Triggering
        • PWM slice event selection의 Block diagram

        • Default mode인 경우 각 slice counter는 Free-running mode(이 Mode에서는 A, B pin 모두 Output pin으로 동작함) 이다.
        • Pin B 가 Input으로 설정된 경우(CC_B는 무시됨)에는 아래와같은 3 가지 Mode(각 slice CSR Rg의 DIVMODE field에서 설정)로 동작(Duty cycle 또는 Frequency 측정에 이용할 수 있음)한다.
          • Pin B가 High level 인 동안 계속 Count 하는 Mode
          • Pin B에 Rising edge 가 검출되면 한번 Count 하는 Mode
          • Pin B에 Falling edge 가 검출되면 한번 Count 하는 Mode
        • Pin B의 신호는 Clock divider에 의하여 Division 되어 Counter(16 Bits)에 입력되기 때문에 상당히 긴 시간 측정이 가능하다.
      • Interrupt Request(IRQ) 와 Interrupt 설정과 상태를 나타내는 Registers
        • PWM 블록은 IRQ 출력을 하나만 갖고 있기 때문에 Interrupt이 발생한 Slices를 판단하고 필요한 Interrupt 처리를 위하여 INTR, INTS, INTE Rg를 이용한다.

        • Interrupt 설정과 상태를 나타내는 INTR(Raw Interrupts Rg), INTS(Interrupt Status Rg), INTE(Interrupt Enable Rg)를 이용하여 어떤 Slices로 부터 Interrupt 가 발생하였는지 판단하고 필요한 처리를 할 수 있다.
          • INTE Rg: 각 Slices의 Interrupt Enable 또는 Disable를 설정한다. INTE Rg의 0 -7번 Bits 가 대응하는 Slices(0 - 7번)의 Interrupt Enable을 설정한다.
          • INTR Rg: 각 Slices(0 - 7번)의 Interrupt 발생 상태(Raw 상태)를 표시한다.
          • INTS Rg: 해당 Slices가 Interrupt Enable로 설정된 상태에서 Interrupt이 발생(INTR Rg의 대응하는 Bit가 Set 됨)하면 INTS Rg의 대응하는 Bit가 Set 된다. INTR Rg의 대응하는 Bit에 1을 Write 하면 INTS Rg의 대응하는 Flag가 Clear 된다.
        • INTR, INTS, INTE Rg를 이용한 Interrupt 처리는 동시에 여러 장치에서 Interrupt가 발생할 수 있게 하고, System interrupt handler가 이 들 Rg를 이용하여 적절한 Interrupt를 처리할 수 있게 한다.
      • 동일한 주파수로 동작하는 여러개 Slices의 위상 제어
        • 일부 PWM을 사용하는 응용(예: Step motor 등)에서는 서로 다른 Slices의 PWM 출력 위상을 서로 다르게 설정할 필요가 있다.

          CSR Rg의 CSR_ADV 와 CSR_RET 필드를 이용하여 Slices의 Counter 값을 한 카운트씩 빠르게 하거나 지연시키는 예

        • EN Register를 이용하여 여러 개의 Slices를 동시에 시작하고 중지할 수 있다. 출력 주파수가 동일한 두 개 이상의 슬라이스가 동시에 시작되고 정지하게 할 수 있다. 그러므로 초기 카운터 값을 조정하는 것에 의하여 각 Slices는 고정 위상 관계를 갖게된다.
        • 각 Slices CSR Rg의 CSR_ADV 와 CSR_RET 필드는 Slices가 실행되는 동안 Slices의 Counter 값을 한 카운트씩 빠르게 하거나 지연시켜서 각 Slices 사이에 일정한 위상차를 갖게할 수 있다. 위 그림과 같이 클럭 활성화 신호(Clock enable)에 펄스를 삽입하거나 삭제하여 이를 수행한다.
        • Counter는 기본 Clock cycle 보다 빠르게 count할 수 없으므로 이 기술을 사용하기 위하여는 Fractional Clock Divider에서 출력되는 신호의 Clock cycle이 기본 Clock cycle보다 낮아야(INT > 1 또는 DIV_FRAC > 0 사용) 한다.
        • 프로그램으로 각 Slices의 CSR_ADV 와 CSR_RET 필드에 1을 Write 하는 방법으로 각 Slices의 위상을 제어(한 카운트씩 빠르게 하거나 지연)할 수 있다.

    • PWM 설정과 제어에 사용하는 레지스터(Registers)
    • 참고자료: "RP2040 Datasheet"의 "4.5.3. List of Registers"를 참고 바람.

      • 각 Slices의 설정과 제어에 사용하는 레지스터(Registers). 8개의 Slice가 동일한 구조이기 때문에 Slice 번호를 x(0 - 7) 문자로 대신 표시한다.
        • CHx_CSR: 각 Slice의 제어 와 상태 표시에 사용되는 Rg(Control and status register).
          • PH_ADV(Bit 7): 이 Bit에 1을 Write 하면 카운터가 실행되는 동안 카운터의 위상을 1 카운트 앞서게 한다.
          • PH_RET(Bit 6): 이 Bit에 1을 Write 하면 카운터가 실행되는 동안 카운터의 위상을 1 카운트 뒤지게 한다.
          • DIVMODE(Bit 5:4): 카운터의 동작 모드를 설정한다.
            • 0x0: Fractional divider에 의하여 설정된 Rate로 Free-running counting 한다.
            • 0x1: Pin B가 High level 인 동안 설정된 Rate로 Count 한다.
            • 0x2: Pin B에 Rising edge 가 검출되면 한번 Count 한다.
            • 0x3: Pin B에 Falling edge 가 검출되면 한번 Count 한다.
          • B_INV(Bit 3): Pin B의 출력이 Invert 된다.
          • A_INV(Bit 2): Pin A의 출력이 Invert 된다.
          • PH_CORRECT(Bit 1): 1 <− Enable phase-correct modulation. 0 <− Trailing-edge
          • EN(Bit 1): PWM channel을 Enable 한다.
        • CHx_DIV: Fractional Clock Divider의 INT와 FRAC 값을 설정한다.

          • INT(Bit 11:4): INT 값을 설정한다.
          • FRAC(Bit 3:0): FRAC 값을 설정한다.
        • CHx_CTR: PWM counter Rg(16 Bits)

          • (Bit 15:0): PWM counter Rg로 16 Bits 값을 직접 읽을 수 있다.
        • CHx_CC: Counter compare values를 설정하는 Rg

          • (Bit 31:16): Out compare unit(Pin B)의 Counter compare values를 설정하는 Rg
          • (Bit 15:0): Out compare unit(Pin A)의 Counter compare values를 설정하는 Rg
        • CHx_TOP: PWM의 TOP 값을 설정하는 Rg

          • (Bit 15:0): Counter wrap(Top) value를 설정
      • EN Register: 이 Rg의 0에서 7번 Bits는 대응하는 채널(0:7)의 CSR_EN 비트에 다른 이름을 부여한 것이다. 그 결과 이 Rg의 여러 Bit에 1을 기록하면 여러 채널을 동시에 활성화 또는 비활성화 할 수 있기 때문에 여러 채널의 실행(동작)을 동기화 할 수 있다.
        • (Bit 7:0): 0에서 7번 Bits는 대응하는 채널(0:7)의 CSR_EN 비트에 다른 이름을 부여한 것으로 동시에 여러 PWM channel을 Enable 할 수 있게 한다.
      • PWM Interrupt 제어에 사용되는 Rg
        • INTR Register(Bit 7:0): Bit 번호에 대응하는 채널(0:7)에 Interrupt가 발생(Raw Interrupts)하는 경우 Set 된다.
        • INTE Register(Bit 7:0): Bit 번호에 대응하는 채널(0:7)의 Interrupt를 Enable 한다.

        • INTS Register(Bit 7:0): Interrupt 상태를 표시하는 Rg. Bit 번호에 대응하는 채널(0:7)의 Interrupt를 Enable된 상태에서 Raw Interrupts가 발생하는 경우, 또는 대응하는 채널(0:7)에 Interrupt Force 명령이 실행된 경우 Set된다.

        • INTF Register(Bit 7:0): Bit 번호에 대응하는 채널(0:7)에 1을 Write하면 해당 채널에 Interrupt가 발생(Interrupt Force)한 것과 같이 동작한다.


  • PWM 설정과 제어 관련 함수 - C/C++ SDK
    • Slices의 설정과 제어에 사용하는 함수
      • 이곳에서는 자주 사용하는 PWM의 설정과 제어에 사용하는 함수에 대하여 설명한다.

        참고자료: Raspberry Pi Pico C/C++ SDK자료 "4.1.18. hardware_pwm"에 PWM의 기능을 설정하는 함수에 대한 전체 설명이 있다.

      • pwm_config_set_clkdiv_mode: PWM configuration에서 PWM의 Counting mode를 설정한다. 기본값은 항상 카운트(free-running PWM) 하는 모드 이고,기타 B pin input이 High level 인 동안만 카운트 하는 모드, rising edge 또는 falling edge 에서 만 카운트 하는 모드로 설정할 수 있다.
        • 기본형: static void pwm_config_set_clkdiv_mode (pwm_config *c, enum pwm_clkdiv_mode mode)
        • 매개 변수
          • c: 수정할 PWM 구성 구조체
          • mode: PWM divide/count mode
      • pwm_config_set_clkdiv: PWM configuration에서 PWM clock divider(clk_sys/div)를 설정한다.
        • 기본형: static void pwm_config_set_clkdiv (pwm_config *c, float div)
        • 매개 변수
          • c: 수정할 PWM 구성 구조체
          • div: counting rate를 감소시키는 값(clk_sys/div)으로 1 보다 크거나 같아야 한다.
      • pwm_config_set_clkdiv_int: PWM configuration에서 PWM clock divider(clk_sys/div)를 설정한다.
        • 기본형: static void pwm_config_set_clkdiv (pwm_config *c, uint div)
        • 매개 변수
          • c: 수정할 PWM 구성 구조체
          • div: counting rate를 감소시키는 값(clk_sys/div)으로 1 보다 크거나 같아야 한다. div는 Integer value 이다.
      • pwm_config_set_output_polarity: PWM configuration에서 Pin A 과 Pin B 출력 극성을 설정한다.
        • 기본형: static void pwm_config_set_output_polarity (pwm_config *c, bool a, bool b)
        • 매개 변수
          • c: 수정할 PWM 구성 구조체
          • a: True 인 경우 Pin A의 출력이 Invert 된다.
          • b: True 인 경우 Pin B의 출력이 Invert 된다.
      • pwm_config_set_phase_correct: PWM configuration에서 Counter의 동작 모드(FAST mode or Phase correction mode)를 설정한다.
        • 기본형: static void pwm_config_set_phase_correct (pwm_config *c, bool phase_correct)
        • 매개 변수
          • c: 수정할 PWM 구성 구조체
          • phase_correct: True인 경우 Phase correction mode, False인 경우 FAST mode(Trailing edge)
      • pwm_config_set_wrap: PWM configuration에서 PWM counter wrap value(Top)를 설정한다.
        • 기본형: static void pwm_config_set_wrap (pwm_config *c, uint16_t wrap)
        • 매개 변수
          • c: 수정할 PWM 구성 구조체
          • wrap: PWM counter wrap value(Top)
      • pwm_get_counter: PWM counter의 현재 값을 가져온다.
        • 기본형: static uint16_t pwm_get_counter (uint slice_num)
        • 매개 변수
          • slice_num: PWM slice 번호
        • Returns: PWM counter의 현재 값
      • pwm_get_default_config: PWM configuration의 기본 설정 값(구조체)를 가져온다.
        • 기본형: static pwm_config pwm_get_default_config (void)
        • Returns: PWM configuration의 기본 설정 값(구조체)
      • pwm_gpio_to_channel: 지정된 GPIO에 연결된 PWM 채널을 확인한다. 각 슬라이스(0에서 7)에는 두 개의 채널 A와 B가 있다.
        • 기본형: static uint pwm_gpio_to_channel (uint gpio)
        • 매개 변수
          • gpio: gpio 번호
        • Returns: 지정된 GPIO를 사용하는 ​​PWM 채널
      • pwm_gpio_to_slice_num: 지정된 GPIO에 연결된 PWM slice를 확인한다. 각 슬라이스(0에서 7)에는 두 개의 채널 A와 B가 있다.
        • 기본형: static uint pwm_gpio_to_slice_num (uint gpio)
        • 매개 변수
          • gpio: gpio 번호
        • Returns: 지정된 GPIO를 사용하는 ​​PWM slice 번호
      • pwm_init: Configuration object에 설정된 대로 지정된 PWM slice를 초기화 한다.
        • 기본형: static void pwm_init (uint slice_num, pwm_config *c, bool start)
        • 매개 변수
          • slice_num: PWM slice 번호
          • c: 수정할 PWM 구성 구조체
          • start: true인 경우 PWM은 구성된 후 시작된다. false인 경우 pwm_set_enabled() 또는 pwm_set_mask_enabled()을 사용하여 수동으로 시작해야 한다.
      • pwm_advance_count: Counter를 실행하는 중에 카운터의 위상을 1 카운트 만큼 앞서게 한다. 이 함수는 위상 앞섬이 완료되면 Return 된다.
        • 기본형: static void pwm_advance_count (uint slice_num)
        • 매개 변수
          • slice_num: PWM slice 번호
      • pwm_retard_count: Counter를 실행하는 중에 카운터의 위상을 1 카운트 만큼 지연 시킨다. 이 함수는 위상 지연이 완료되면 Return 된다.
        • 기본형: static void pwm_retard_count (uint slice_num)
        • 매개 변수
          • slice_num: PWM slice 번호
      • pwm_set_both_levels: PWM Counter 비교 값(Pin A와 Pin B 출력제어에 사용)의 설정. 비교 값을 저장하는 Counter Compare Rg는 Double-buffered 되어 Counter 가 동작 중에 Write 하여도 Counter 값이 wraps 될 때 Counter Compare Rg의 값이 변경된다.
        • 기본형: static void pwm_set_both_levels (uint slice_num, uint16_t level_a, uint16_t level_b)
        • 매개 변수
          • slice_num: PWM slice 번호
          • level_a: Pin A 출력 제어를 위한 비교 값. Counter 가 이 값에 도달하면 Pin A 출력이 Toggle 된다.
          • level_b: Pin B 출력 제어를 위한 비교 값. Counter 가 이 값에 도달하면 Pin B 출력이 Toggle 된다.
      • pwm_set_chan_level: 선택한 Pin(slice, channel)의 출력을 제어한다.
        • 기본형: static void pwm_set_chan_level (uint slice_num, uint chan, uint16_t level)
        • 매개 변수
          • slice_num: PWM slice 번호
          • chan: channel 번호. 0인 경우 A channel, 1인 경우 B channel
          • level: 선택한 Pin(slice, channel)의 출력 제어를 위한 비교 값. Counter 가 이 값에 도달하면 선택한 Pin 출력이 Toggle 된다.
      • pwm_set_clkdiv: PWM Clock 분배기를 설정한다. Counter는 sysclock를 이 값으로 나눈 값으로 증가한다.
        • 기본형: static void pwm_set_clkdiv (uint slice_num, float divider)
        • 매개 변수
          • slice_num: PWM slice 번호
          • divider: Floating point clock divider, 1.f <= value < 256.f
      • pwm_set_clkdiv_int_frac: Clock divider를 설정한다.
        • 기본형: static void pwm_set_clkdiv_int_frac (uint slice_num, uint8_t integer, uint8_t fract)
        • 매개 변수
          • slice_num: PWM slice 번호
          • integer: Clock divider의 8비트 정수 부분
          • fract: Clock divider의 4 bit fractional 부분
      • pwm_set_clkdiv_mode: PWM divider mode를 설정한다.
        • 기본형: static void pwm_set_clkdiv_mode (uint slice_num, enum pwm_clkdiv_mode mode)
        • 매개 변수
          • slice_num: PWM slice 번호
          • mode: Divider mode. PWM_DIV_FREE_RUNNING = 0, PWM_DIV_B_HIGH = 1, PWM_DIV_B_RISING = 2, PWM_DIV_B_FALLING = 3
            • PWM_DIV_FREE_RUNNING: Fractional divider에 설정된 비율로 Free-running counting을 한다. A, B pin 모두 Output pin으로 동작한다.
            • PWM_DIV_B_HIGH: Pin B가 High level 인 동안 계속 Count 한다.
            • PWM_DIV_B_RISING: Pin B에 Rising edge 가 검출되면 한번 Count 한다.
            • PWM_DIV_B_FALLING: Pin B에 Falling edge 가 검출되면 한번 Count 한다.
      • pwm_set_counter: PWM counter 값을 설정한다.
        • 기본형: static void pwm_set_counter (uint slice_num, uint16_t c)
        • 매개 변수
          • slice_num: PWM slice 번호
          • c: PWM counter를 설정할 값
      • pwm_set_enabled: PWM을 Enable/Disable 한다.
        • 기본형: static void pwm_set_enabled (uint slice_num, bool enabled)
        • 매개 변수
          • slice_num: PWM slice 번호
          • enabled: true인 경우 PWM이 Enable 되고, False인 경우 Disable 된다.
      • pwm_set_mask_enabled: 한 번에 여러개의 PWM를 Enable 한다.
        • 기본형: static void pwm_set_mask_enabled (uint32_t mask)
        • 매개 변수
          • mask: Enable 또는 Disable할 PWM의 Bitmap. Bit 0~7은 각각 slice 0~7을 Enable/Disable 한다.
      • pwm_set_gpio_level: 주어진 GPIO(해당 slice(0 ~ 7)와 channel(A or B))의 Counter-compare field를 업데이트 한다.
        • 기본형: static void pwm_set_gpio_level (uint gpio, uint16_t level)
        • 매개 변수
          • gpio: gpio 번호. gpio 번호가 결정되면 대응하는 slice(0 ~ 7)와 channel(A or B)이 결정된다.
          • level: 선택된 GPIO를 위한 PWM 레벨(level) 값
      • pwm_set_output_polarity: PWM 출력 극성을 설정한다.
        • 기본형: static void pwm_set_output_polarity (uint slice_num, bool a, bool b)
        • 매개 변수
          • slice_num: PWM slice 번호
          • a: true 인 경우 Pin A의 출력을 Invert 한다.
          • b: true 인 경우 Pin B의 출력을 Invert 한다.
      • pwm_set_phase_correct: PWM phase correct mode를 on/off 한다..
        • 기본형: static void pwm_set_phase_correct (uint slice_num, bool phase_correct)
        • 매개 변수
          • slice_num: PWM slice 번호
          • phase_correct: true 인 경우 phase correct modulation으로 설정되고, false 인 경우 Trailing edge modulation(FAST PWM Mode)으로 설정된다.
      • pwm_set_wrap: PWM counter의 wrap 값을 설정한다.
        • 기본형: static void pwm_set_wrap (uint slice_num, uint16_t wrap)
        • 매개 변수
          • slice_num: PWM slice 번호
          • wrap: 설정할 wrap(Top) 값
    • PWM Interrupt 관련 함수
      • pwm_set_irq_enabled: 지정한 PWM의 Interrupt를 Enable 한다.
        • 기본형: static void pwm_set_irq_enabled (uint slice_num, bool enabled)
        • 매개 변수
          • slice_num: Enable 또는 Disable할 PWM slice 번호
          • enabled: true인 경우 PWM이 Enable 되고, False인 경우 Disable 된다.
      • pwm_set_irq_mask_enabled: 한 번에 여러개의 PWM Interrupt를 Enable또는 Disable 한다.
        • 기본형: static void pwm_set_irq_mask_enabled (uint32_t slice_mask, bool enabled)
        • 매개 변수
          • slice_mask: Enable 또는 Disable할 모든 PWM slice의 Bitmask. Bitmask의 Bit 위치(번호)에 대응하는 번호의 PWM slice가 Enable 또는 Disable 된다.
          • enabled: true인 경우 PWM이 Enable 되고, False인 경우 Disable 된다.
      • pwm_get_irq_status_mask: 현재 PWM interrupt status(raw)를 갖어온다.
        • 기본형: static uint32_t pwm_get_irq_status_mask (void)
        • Returns: 현재 모든 PWM 인터럽트의 상태를 표시하는 Bitmask
      • pwm_clear_irq: PWM channel interrupt를 Clear 한다.
        • 기본형: static void pwm_clear_irq (uint slice_num)
        • 매개 변수
          • slice_num: PWM slice 번호
      • pwm_force_irq: PWM 인터럽트를 강제로 실행한다.
        • 기본형: static void pwm_force_irq (uint slice_num)
        • 매개 변수
          • slice_num: PWM slice 번호

    • PWM을 사용하는 프로그램 예
      • PWM을 이용하여 LED의 밝기를 제어하는 프로그램 예
        • 이 예는 PWM을 이용한 DC 전력제어(예: LED 밝기제어, DC 모터 속도제어 등) 기술를 이해하기 위한 것이다.

        • LED의 밝기를 제어하는 프로그램 예: pwm-led-brigth-cont.c
        • 실험을 위한 준비
          • LED: 개발보드에 내장(GPIO25)되어 있기 때문에 별도의 회로를 필요로 하지 않는다.
        • 실험 방법
          • "새 Project를 생성하고 Build 하기"를 참고하여 pwm-led-brigth-cont Project를 생성한다.
          • 위 프로그램을 복사하여 Project 내의 "pwm-led-brigth-cont.c"에 저장 한다.
          • "새 Project를 생성하고 Build 하기"를 참고하여 Project를 Build 한다.
          • 주: 처음 Project를 생성한 다음 nmake를 실행하면 AhnLab V3 바이러스 프로그램이 설치된 경우 malware/Win.Generic.C4992917 바이러스가 발견되었다는 메세지가 출력되고 Fatal error 가 발생하여 컴파일이 중단된다. 그러나 Error 메세지를 무시하고 한번더 nmake를 실행하면 컴파일이 잘 진행된다.

            주: AhnLab V3 바이러스 프로그램의 Home -> 보안 상태 설정에서 PC 실시간 검사를 Off 상태로 하면 이 문제가 발생하지 않음.

          • "Build 한 프로그램을 Pi Pico 보드에 Load(Flashing) 하고 실행하기"를 참고하여 pwm-led-brigth-cont.uf2를 Pi Pico 보드에 Upload 하여 실행한다.
          • 참고: Project를 Build 할 때 "hardware/pwm.h"를 발견할 수 없다는 오류 메세지가 발생(SDK에 오류가 있는 것 같음)할 수 있다. 이 경우 pico-sdk\src\rp2_common\hardware_pwm\include 폴더에 있는 hardware 폴더(이 폴더에 pwm.h 파일이 있음)를 pwm-led-brigth-cont.c 프로그램이 있는 폴더에 복사한 다음 Project를 Build 한다.

          • 실험
            • 프로그램이 실행되면 LED(GPIO25)의 밝기가 약 1초 간격으로 점점 밝아지고 어두어 지기를 반복한다.

      • PWM을 이용한 Pulse 발생과 Pulse Width 측정 프로그램 예
        • 펄스폭 측정을 위한 회로 구성 예

          펄스폭 측정 프로그램 이해를 위한 PWM 모듈의 신호 설명

        • 펄스폭 측정 프로그램 이해를 위한 PWM 모듈의 동작 설명
          • PWM을 이용한 피 측정 신호(Pulse) 발생
            • PWM는 간단한 설정만으로 Pulse 폭 제어가 가능한 Pulse를 발생시키는 장치이기 때문에 실험에 필요한 Pulse 신호 발생에 PWM를 사용한다.
            • 피 측정 신호를 발생 시키는 PWM 모듈의 Top과 Clock Divider의 DIV_INT, CC Rg의 Level, 동작 모드(PWM_DIV_FREE_RUNNING)를 설정하면 Fig.a 와 같이 PWM 모듈의 Counter 값은 0에서 Top 까지 Count를 계속한다.
            • 피 측정 신호를 발생 시키는 PWM 모듈은 Fig.a 와 같이 PWM 모듈의 Counter 값이 Pulse width 설정 값 보다 작으면 High 가 되고 크면 Low 가 되는 Pulse 신호(Fig.b)를 출력한다.
            • 피 측정 신호를 발생 시키는 PWM 모듈의 출력(Fig.b)을 Pulse 폭 측정을 위한 PWM의 입력(Pin B)에 연결한다.
          • PWM을 이용한 Pulse 폭 측정
            • Pulse 폭 측정을 위한 PWM의 Clock Divider의 DIV_INT를 설정한다.
            • PWM의 동작 모드를 PWM_DIV_B_HIGH로 설정한다.
              • 이 모드에서 PWM는 입력(Pin B)이 High인 동안만 Clock Divider에 의하여 설정된 비율로 Count 하는 Counter(Counter의 초기 값이 0이 상태에서 출발)로 동작한다.
              • Pin B 신호가 High인 동안 PWM의 카운터 값은 Fig. c와 같이 시간에 비례하여 일정한 비율로 증가한다.
            • Pulse 폭 측정을 위한 PWM의 입력(Pin B) 신호의 Falling edge(Fig.b Pulse의 Falling edge)에서 Interrupt 가 발생하도록 설정한다.
              • Pin B 신호가 High에서 Low 상태가 되면 PWM 카운터의 Count는 정지된다. 이 때 카운터는 입력 Pulse 신호의 펄스 폭에 비례한 값을 저장하고 있게 된다..
              • 또한 이 순간(Fig.b Pulse의 Falling edge) Falling edge Interrupt 가 발생하여 Interrupt handler 가 실행된다.
              • Interrupt handler에서 PWM의 카운터의 값(측정된 Pluse 폭)을 pulseWidthMeasue 변수에 저장하고,
              • 다음 주기 Pulse 신호의 폭을 측정하기 위하여 PW의 Counter의 값을 0로 초기화한다.
          • 측정 결과를 모니터에 출력하기
            • 측정된 모든 결과를 모니터에 출력할 수 없기 때문(모니터에 mSec 단위로 반복 측정하는 테이터를 직접 출력하면 너무 빠른 출력으로 판독 불가 상태로 됨)에 이 예에서는 Timer를 이용하여 1초 주기의 Interrupt를 발생 시키고 이 Interrupt handler에서 측정 결과를 출력한다.
            • 또한 이 Interrupt handler에서 버튼 Switch의 상태에 따라 측정 신호의 Pulse 폭 설정을 변경한다.
            • 그 결과 버튼을 1초 이상 계속 누르고 있으면 매 1초 간격으로 반복하여 Pulse 폭 설정을 변경하는 효과를 얻을 수 있다.

        • PWM을 이용한 Pulse 발생과 Pulse Width를 측정하는 프로그램 예: pwm-pulse-width-measure.c
        • 실험을 위한 준비
          • 피 측정 Pulse 신호 출력(GPIO20)과 측정 신호 입력(GPIO19) Pin을 연결 한다.
          • GP21과 GP22에 Button SW를 연결한다.
          • Pi Pico 개발보드와 PC의 UART 신호 연결
            • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 RXD와 Pi Pico 개발보드의 TXD1(GP4)를 연결한다.
            • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 TXD와 Pi Pico 개발보드의 RXD1(GP5)를 연결한다.
            • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 GND와 Pi Pico 개발보드의 GND를 연결한다.
            • 주의: 컴퓨터(USB --> UART(RS232) 변환 모듈)의 전원 전압(Vdd)과 Pi Pico 개발보드의 전원 전압(Vdd)은 서로 연결하지 않는다. USB --> UART와 Pi Pico 개발보드의 전원 전압(Vdd)은 서로 다를 수 있다.

        • 실험 방법
          • "새 Project를 생성하고 Build 하기"를 참고하여 pwm-pulse-width-measure Project를 생성한다.
          • 위 프로그램을 복사하여 Project 내의 "pwm-pulse-width-measure.c"에 저장 한다.
          • UART0를 printf의 출력으로 사용하기 때문에 "pwm-pulse-width-measure.c"이 있는 폴더의 CMakeLists.txt 파일에서 pico_enable_stdio_uart"를 아래와 같이 설정 하여야 한다.
          • pico_enable_stdio_uart(pwm-pulse_width_measure 1)

          • "새 Project를 생성하고 Build 하기"를 참고하여 Project를 Build 한다.
          • "Build 한 프로그램을 Pi Pico 보드에 Load(Flashing) 하고 실행하기"를 참고하여 pwm-pulse-width-measure.uf2를 Pi Pico 보드에 Upload 하여 실행한다.
          • 주: PC에서 모니터 프로그램이 실행 중인 상태에서 Pi Pico 보드에 pwm-pulse-width-measure.uf2를 Upload 하면, 오류가 발생할 수 있기 때문에 프로그램을 Pi Pico 보드에 Upload 한 다음 PC에서 모니터 프로그램을 실행하여야 한다.

          • PC에서 모니터 프로그램(예: OC-Console, Tera Term)을 설치(이미 설치되어 있는 경우에는 실행만 하면됨)하고 실행 한다.
          • 모니터 프로그램에서 USB --> UART(RS232) 변환 모듈의 Serial Port를 확인하고 필요한 설정(Serial Port와 Baudrate(115200) 등을 설정)을 한다.
          • 참고: Project를 Build 할 때 "hardware/pwm.h"를 발견할 수 없다는 오류 메세지가 발생(SDK에 오류가 있는 것 같음)할 수 있다. 이 경우 pico-sdk\src\rp2_common\hardware_pwm\include 폴더에 있는 hardware 폴더(이 폴더에 pwm.h 파일이 있음)를 pwm-pulse-width-measure.c 프로그램이 있는 폴더에 복사한 다음 Project를 Build 한다.

          • 실험
            • 프로그램이 실행되면 측정된 펄스 폭이 PC 모니터에 출력된다.
              • System clock의 한 주기(1 Count): (1/clk_sys(125MHz)) = 0.008uSec
              • 피 측정 Pulse 발생 PWM의 Top = 0xffffu(65535), 초기 펄스폭 설정 = 30000 로 설정하고,
              • 피 측정 펄스 폭 측정 PWM와 펄스 폭 측정을 위한 PWM의 Count 비를 1/125로 동일하게 설정하였기 때문에 측정 결과는 설정 값과 같게 된다.
              • 펄스 폭 측정 PWM clock의 한 주기(1 Count)는 0.008uSec x 125 = 1uSec 가 된다.
              • 측정 결과 Count 값이 30000인 경우 펄스폭은 30000uSec 가 된다.
            • 1초 간격으로 측정 결과를 출력하는 함수에서 Up, Down 버튼의 상태에 따라 펄스 폭 설정을 변경하도록 하였기 Up, Down 버튼을 1초 정도 누르고 있어야 버튼의 상태를 읽을 수 있다.
              • GPIO21 버튼을 누르고 있으면 펄스 폭이 증가하고, GPIO22 버튼을 누르고 있으면 펄스 폭이 감소한다.
              • Up, Down 버튼의 PULSE_STEP을 2000으로 설정하였기 때문에 버튼을 계속 누르고 있으면 매 1초 마다 측정 값이 약 2000씩 증가 또는 감소 한다.

      • PWM을 이용한 Pulse 발생과 Pulse Frequency 측정 프로그램 예
        • 주파수 측정을 위한 회로 구성 예

        • 주파수 측정 프로그램 이해를 위한 PWM 모듈의 동작 설명
          • PWM을 이용한 피 측정 신호(Pulse) 발생
            • PWM는 간단한 설정만으로 Pulse 폭과 주기(주파수 = 1/주기) 제어가 가능한 Pulse를 발생시키는 장치이기 때문에 실험에 필요한 Pulse 신호 발생에 PWM를 사용한다.
            • 피 측정 신호를 발생 시키는 PWM 모듈의 Top과 Clock Divider의 DIV_INT, CC Rg의 Level, 동작 모드(PWM_DIV_FREE_RUNNING)를 설정하면 PWM 모듈의 Counter 값은 0에서 Top 까지 Count를 계속한다.
            • 일정한 속도로 Counter 값이 0에서 Top 까지 Count하기 때문에 Top 값을 크게 설정하면 발생되는 펄스의 주기가 길어지고(주파수는 낮아짐), Top 값을 작게 설정하면 발생되는 펄스의 주기가 짧아(주파수는 높아짐) 진다.
            • 피 측정 신호를 발생 시키는 PWM 모듈은 Counter 값이 Pulse width 설정 값 보다 작으면 High 가 되고 크면 Low 가 되는 Pulse 신호를 출력한다.
            • 피 측정 신호를 발생 시키는 PWM 모듈의 출력을 Pulse 폭 측정을 위한 PWM의 입력(Pin B)에 연결한다.
          • PWM을 이용한 Pulse 주파수(주파수 = 1/주기) 측정
            • PWM의 동작 모드를 PWM_DIV_B_RISING(Rising edge에서 Counter 값이 1 씩 증가)로 설정한다.
          • 측정 결과를 모니터에 출력하기
            • Timer를 이용하여 1초 주기의 Interrupt를 발생 시키고 이 Interrupt handler에서 측정 결과(1초 동안 PWM가 Count한 값)를 출력한다.
            • 매 1초 동안 Count 한 값을 출력하기 위하여 측정 결과(1초 동안 PWM가 Count한 값)를 출력한 다음, PWM Counter 값을 0으로 초기화 한다.
            • 또한 이 Interrupt handler에서 버튼 Switch의 상태에 따라 측정 신호의 Top 설정을 변경한다.
            • 그 결과 버튼을 1초 이상 계속 누르고 있으면 매 1초 간격으로 반복하여 Top 설정을 변경하는 효과를 얻을 수 있다.

        • PWM을 이용한 Pulse 발생과 Pulse 주파수를 측정하는 프로그램 예: pwm-frequency-measure.c
        • 실험을 위한 준비
          • 피 측정 Pulse 신호 출력(GPIO20)과 측정 신호 입력(GPIO19) Pin을 연결 한다.
          • GP21과 GP22에 Button SW를 연결한다.
          • Pi Pico 개발보드와 PC의 UART 신호 연결
            • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 RXD와 Pi Pico 개발보드의 TXD1(GP4)를 연결한다.
            • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 TXD와 Pi Pico 개발보드의 RXD1(GP5)를 연결한다.
            • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 GND와 Pi Pico 개발보드의 GND를 연결한다.
            • 주의: 컴퓨터(USB --> UART(RS232) 변환 모듈)의 전원 전압(Vdd)과 Pi Pico 개발보드의 전원 전압(Vdd)은 서로 연결하지 않는다. USB --> UART와 Pi Pico 개발보드의 전원 전압(Vdd)은 서로 다를 수 있다.

        • 실험 방법
          • "새 Project를 생성하고 Build 하기"를 참고하여 pwm-frequency-measure Project를 생성한다.
          • 위 프로그램을 복사하여 Project 내의 "pwm-frequency-measure.c"에 저장 한다.
          • UART0를 printf의 출력으로 사용하기 때문에 "pwm-frequency-measure.c"이 있는 폴더의 CMakeLists.txt 파일에서 pico_enable_stdio_uart"를 아래와 같이 설정 하여야 한다.
          • pico_enable_stdio_uart(pwm-pulse_width_measure 1)

          • "새 Project를 생성하고 Build 하기"를 참고하여 Project를 Build 한다.
          • "Build 한 프로그램을 Pi Pico 보드에 Load(Flashing) 하고 실행하기"를 참고하여 pwm-frequency-measure.uf2를 Pi Pico 보드에 Upload 하여 실행한다.
          • 주: PC에서 모니터 프로그램이 실행 중인 상태에서 Pi Pico 보드에 pwm-frequency-measure.uf2를 Upload 하면, 오류가 발생할 수 있기 때문에 프로그램을 Pi Pico 보드에 Upload 한 다음 PC에서 모니터 프로그램을 실행하여야 한다.

          • PC에서 모니터 프로그램(예: OC-Console, Tera Term)을 설치(이미 설치되어 있는 경우에는 실행만 하면됨)하고 실행 한다.
          • 모니터 프로그램에서 USB --> UART(RS232) 변환 모듈의 Serial Port를 확인하고 필요한 설정(Serial Port와 Baudrate(115200) 등을 설정)을 한다.
          • 참고: Project를 Build 할 때 "hardware/pwm.h"를 발견할 수 없다는 오류 메세지가 발생(SDK에 오류가 있는 것 같음)할 수 있다. 이 경우 pico-sdk\src\rp2_common\hardware_pwm\include 폴더에 있는 hardware 폴더(이 폴더에 pwm.h 파일이 있음)를 pwm-frequency-measure.c 프로그램이 있는 폴더에 복사한 다음 Project를 Build 한다.

          • 실험
            • 프로그램이 실행되면 측정된 펄스 주파수가 PC 모니터에 출력된다.
              • System clock의 한 주기(1 Count): (1/clk_sys(125MHz)) = 0.008uSec
              • 피 측정 Pulse 발생 PWM의 한 주기(1 Count)는 0.008uSec x 125 = 1uSec 가 된다.
              • Top을 2000으로 설정한 경우 피 측정 Pulse의 주기는 2000uSec 가 되고 주파수는 1/2000uSec = 500Hz 가 된다.
            • 1초 간격으로 측정 결과를 출력하는 함수에서 Up, Down 버튼의 상태에 따라 펄스 Top 설정을 변경하도록 하였기 때문에 Up, Down 버튼을 1초 정도 누르고 있어야 버튼의 상태를 읽을 수 있다.
              • GPIO21 버튼을 누르고 있으면 펄스 주파수 증가하고, GPIO22 버튼을 누르고 있으면 펄스 주파수가 감소한다.
              • Up, Down 버튼의 TOP_STEP을 500으로 설정하였기 때문에 버튼을 계속 누르고 있으면 매 1초 마다 측정 값이 증가 또는 감소 한다.

    • Pico PWM(Pulse width modulation) 관련 페이지 보기