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

timer-pico-c

Pi Pico Timer - C/C++ SDK
Raspberry Pi Pico Timer - C/C++ SDK


  • Raspberry Pi Pico Timer
    • Raspberry Pi Pico Timer 개요
      • 참고자료: "RP2040 Datasheet A microcontroller by Raspberry Pi" 4.6.Timer

      • RP2040의 Timer
        • RP2040의 시스템 Timer는 시스템을 위한 마이크로초 타임베이스(microsecond timebase)를 제공하며, 이 타임베이스를 기반으로 Timer 인터럽트를 생성한다.

        • RP2040의 시스템 Timer의 중요한 기능은 아래와 같다.
          • 매 Microsecond 마다 1씩 증가하는 Single 64-bit counter
          • 이 카운터는 32비트 버스를 통해 한 쌍의 래치 레지스터(64-bit를 32-bit 씩 2번 읽음)에서 읽을 수(race-free) 있다.
          • 64-bit Counter 값을 읽는 경우 Lower register(TIMELR)를 먼저 읽으면 Higher register(TIMEHR) 값은 Latches 되기 때문에 정확한 64-bit Counter 값을 읽을 수 있다.
          • 카운터의 하단 32비트와 일치할 경우 IRQ를 발생 시키는 4개의 Alarm 레지스터를 갖고 있다.
          • Microsecond 단위의 시간을 카운트 하는 64-bit 카운터는 수천 년 동안 Overflow 가 발생하지 않기 때문에 아주 용이하게 시간과 관련한 많은 기능을 수행할 수 있다.
      • Alarms
        • Timer에는 4개의 Alarm 레지스터를 갖고 있으며, 각 Alarm은 별도의 인터럽트를 발생할 수 있다.
        • Alarm은 64-bit Counter의 하위 32비트와 일치하는 경우 발생하기 때문에 최대 232 Microseconds(4295 seconds or 72 minutes) 후에 알람을 발생 시킬 수 있다.
        • 만약 더 오랜 시간 후에 Alarm을 발생 시키고자 하는 경우에는 참고자료: "RP2040 Datasheet A microcontroller by Raspberry Pi" 4.8. RTC를 참고 바람.
        • Alarm을 Enable 하는 방법
          • 사용하려는 Alarm의 Interrupt를 아래 예와 같이 Enable 한다.
          • hw_set_bits(&timer_hw->inte, 1u << ALARM0);

          • Alarm irq의 Interrupt handler를 아래 예와 같이 설정한다.
          • irq_set_exclusive_handler(ALARM_IRQ, alarm_irq);

          • Alarm interrupt를 아래 예와 같이 Enable 한다.
          • irq_set_enabled(ALARM_IRQ, true);

          • Alarm 발생 시간을 아래 예와 같이 설정한다. 이 예는 Alarm 이 64-bit Counter의 하위 32비트와 일치하는 경우의 예 이다.
          • uint64_t target = timer_hw->timerawl + delay_us;

            timer_hw->alarm[ALARM0] = (uint32_t) target;

    • Timer와 Alarm을 사용하는 Coding 예
      • Reading the time
        • RP2040의 Timer counter는 2개의 32 counter(64 bits)로 구성되어 있다. RP2040는 32Bits Data bus를 사용하기 때문에 계속하여 변동하는 Timer counter(64 bits)를 안정적으로 읽기 위하여 Latchs Rg를 사용(TIMELR을 읽는 순간 TIMEHR Rg의 값이 Latchs Rg에 저장되어 변동하지 않도록함)한다.
        • 64-bit Timer counter의 값을 읽는 예
      • Alarm 설정하기
        • Alarm을 설정하는 Coding 예(전체 프로그램은 "Hardware Structs Library를 이용한 프로그램 예"를 참고 바람)
    • 자주 사용하는 Registers
      • 참고자료: "RP2040 A microcontroller by Raspberry Pi" 4.6.5.List of Registers

      • Timer/Counter Rg
        • TIMEHW: Timer counter 63:32 Bits에 쓰기. TIMEHW를 Write 하기 전에 TIMELW를 먼저 Write 하여야 한다.
        • TIMELW: Timer counter 31:0 Bits에 쓰기. TIMEHW를 Write 하여야 전제 Timer 값이 Timer counter에 복사된다.
        • TIMEHR: Timer counter 63:32 Bits 읽기(Latchs Rg를 사용함). TIMEHR를 Read 하기 전에 TIMELR를 먼저 Read 하여야 한다.
        • TIMELR: Timer counter 31:0 Bits 읽기.
        • TIMERAWH: Timer counter 63:32 Bits를 Latchs Rg를 사용하지 않고 바로 읽기.
        • TIMERAWL: Timer counter 31:0 Bits를 Latchs Rg를 사용하지 않고 바로 읽기.
      • Alarm Rg
        • ALARM0: Alarm 0의 Alarm 시간(Fire time)을 설정한다.
        • ALARM1: Alarm 1의 Alarm 시간(Fire time)을 설정한다.
        • ALARM2: Alarm 2의 Alarm 시간(Fire time)을 설정한다.
        • ALARM3: Alarm 3의 Alarm 시간(Fire time)을 설정한다.
        • 알람이 설정되면 TIMER_ALARMx == TIMELR 일 때 알람이 발생한다. 알람이 발생하면 자동으로 알람이 해제된다. 알람이 발생하기 전에 ARMED 상태 레지스터를 사용하여 알람을 해제할 수 있다. x 는 0 - 3 값을 갖는다.

        • ARMED: 각 알람의 설정/해제 상태를 표시한다. ALARMx 레지스터에 Write가 실행되면 x 번 알람이 자동으로 설정된다. 알람이 발생하면 자동으로 알람 설정이 해제된다. 알람이 발생하기 전에 ARMED 상태 레지스터의 x 번 알람 해당 Bit에 1을 Write 하면 알람이 해제된다.
      • Interrupts Rg
        • INTR: Raw Interrupts Register
        • INTE: Interrupt Enable Register
        • INTF: Interrupt Force Register
        • INTS: Interrupt status Register

  • Library Structure와 Library 사용 예 - C/C++ SDK
    • Library Structure
      • Hardware Registers Library
        • Hardware Registers Library는 RP2040 registers 주소를 모두 포함하는 Library 이다. 이 Library는 RP2040 registers를 직접 Access 하는데 사용된다. C/C++ 프로그램에서는 Hardware Registers Library를 직접 사용하는 것 보다 아래 Hardware Structs Library를 사용하는 것이 좀더 C/C++ 프로그램을 읽기 쉽게 한다.
        • Hardware Registers Library 예: 이 파일에 RP2040 Timer 관련 Rg 주소가 모두 Define 되어 있다.
        • 참고자료: pico-sdk 설치 폴더(pico-sdk\src\rp2040\hardware_regs\include\hardware\regs\timer.h)의 timer.h를 편집기로 열어 전체 파일을 볼 수 있다.

          c 프로그램에서 이 파일을 직접 사용하는 것 보다 아래 Hardware Structs Library를 사용(Hardware Structs Library에서 이 파일을 사용)하여 RP2040 Rg에 접근한다.

      • Hardware Structs Library
        • Hardware Structs Library는 RP2040 System address space 상의 RP2040 registers를 직접 Access 할 수 있도록 하는 C 구조체를 제공하기 때문에 이 Library를 사용하여 RP2040 registers를 직접 Access 할 수 있다.
        • Timer를 위한 Hardware Structs Library 예:
        • 참고자료: pico-sdk 설치 폴더(pico-sdk\src\rp2040\hardware_structs\include\hardware\structs\timer.h)의 timer.h를 편집기로 열어 전체 파일을 볼 수 있다.

          Hardware Structs Library를 이용하여 Alarm을 설정하는 Coding 예. RP2040 Rg에 접근할 수 있는 구조체를 사용하여 C 언어에서 RP2040 Rg에 직접 R/W 할 수 있다.

          uint64_t target = timer_hw->timerawl + delay_us;

          timer_hw->alarm[ALARM_NUM] = (uint32_t) target;

      • Hardware Support Libraries
        • Hardware Support Libraries는 Hardware/peripheral을 용이하게 사용할 수 있도록 Hardware Structs Library에 비교하여 조금 높은 수준의 추상화를 제공한다. C/C++ 함수를 사용하여 RP2040 Rg에 접근하기 때문에 Hardware Structs Library에 비교하여 효율성은 떨어지지만 Hardware에 친숙하지 않은 프로그램어도 용이하게 프로그램을 작성할 수 있다.
        • 참고자료: "Raspberry Pi Pico C/C++ SDK Libraries and tools for C/C++ development on RP2040 microcontrollers" 4.1.23. hardware_timer

      • Higher-level Libraries
        • Higher-level Libraries는 Hardware Support Libraries에 비교하여 더 높은 수준의 추상화를 제공하기 때문에 일반적으로 C/C++ 프로그램 작성을 더 용이하게 한다. 그러나 효율성은 떨어지기 때문에 높은 수준의 속도와 정밀성을 요구하는 프로그램에는 적합하지 않을 수 있다.
        • 참고자료: "Raspberry Pi Pico C/C++ SDK Libraries and tools for C/C++ development on RP2040 microcontrollers" 4.2.12. alarm, 4.2.13. repeating_timer

    • Hardware Structs Library를 이용한 프로그램 예
      • Alarm interrupt를 사용하여 일정한 주기를 발생 시키는 프로그램 예: timer-alarm-led-hw-structs.c
      • 실험을 위한 준비
        • LED: 개발보드에 내장(GPIO25)되어 있기 때문에 별도의 회로를 필요로 하지 않는다.
      • 실험 방법

    • Hardware Support Libraries를 이용한 프로그램 예
      • Repeating_timer 함수를 사용하여 일정한 주기를 발생 시키는 프로그램 예: timer-alarm-led-hw-support.c
      • 실험을 위한 준비
        • LED: 개발보드에 내장(GPIO25)되어 있기 때문에 별도의 회로를 필요로 하지 않는다.
      • 실험 방법
    • Higher-level Libraries를 이용한 프로그램 예
      • Repeating_timer 함수를 사용하여 일정한 주기를 발생 시키는 프로그램 예: timer-rept-led-hi-level.c
      • 실험을 위한 준비
        • LED: 개발보드에 내장(GPIO25)되어 있기 때문에 별도의 회로를 필요로 하지 않는다.
      • 실험 방법

  • Raspberry Pi Pico Timer 프로그램 예
    • 프로그램 예: Timer interrupt를 이용한 Switch debouncing
      • 이 예는 Timer를 이용하여 일정한 시간 후에 Interrupt를 발생 시키는 방법과 Callback function의 이해를 위한 것이다. 이 예는 일정한 시간이 지난 다음 발생하는 Interrupt를 이용하여 스위치에서 발생하는 Bouncing 문제를 해결(Debouncing) 하는 예 이다.

        아래 그림은 Switch의 금속 접점이 이상적이지 않기 때문에 Switch를 Closed 하거나 Open 하는 순간에 발생하는 Bouncing 현상 예 이다. Bouncing은 Switch의 상태에 따라 대략 5mSec - 10mSec 사이에 발생 한다.

        소프트웨어로 Bouncing 문제를 해결(Debouncing) 하는 방법은 처음 Switch 누름을 인지한 다음 약 15mSec - 30mSec 후, Switch 상태를 다시 확인하여 이 때 까지 누름 상태가 지속되는 경우 누름 상태로 판단한다.

      • SW Debouncing 프로그램 예: sw_debounc_timer_int.c
      • 실험을 위한 준비
        • GP22에 Button SW를 연결한다
        • Pi Pico 개발보드와 PC의 UART 신호 연결: Default Serial 통신 Port(printf 사용)로 UART0를 사용한다.
          • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 RXD와 Pi Pico 개발보드의 TXD0(GP0: 1번 Pin)를 연결한다.
          • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 TXD와 Pi Pico 개발보드의 RXD0(GP1: 2번 Pin)를 연결한다.
          • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 GND와 Pi Pico 개발보드의 GND를 연결한다.
          • 주의: 컴퓨터(USB --> UART(RS232) 변환 모듈)의 전원 전압(Vdd)과 Pi Pico 개발보드의 전원 전압(Vdd)은 서로 연결하지 않는다. USB --> UART와 Pi Pico 개발보드의 전원 전압(Vdd)은 서로 다를 수 있다.

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

        • "새 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) 하고 실행하기"를 참고하여 sw_debounc_timer_int.uf2를 Pi Pico 보드에 Upload 하여 실행한다.
        • 주: PC에서 모니터 프로그램이 실행 중인 상태에서 Pi Pico 보드에 sw_debounc_timer_int.uf2를 Upload 하면, 오류가 발생할 수 있기 때문에 프로그램을 Pi Pico 보드에 Upload 한 다음 PC에서 모니터 프로그램을 실행하여야 한다.

        • PC에서 모니터 프로그램(예: OC-Console, Tera Term)을 설치(이미 설치되어 있는 경우에는 실행만 하면됨)하고 실행한다.
        • 모니터 프로그램에서 USB --> UART(RS232) 변환 모듈의 Serial Port를 확인하고 필요한 설정(Serial Port와 Baudrate(115200) 등을 설정)을 한다.
        • 실험
          • GP22에 연결된 Button SW를 누르면 SW를 누른 회수가 모니터에 출력된다.

    • 프로그램 예: Timer counter를 이용한 Pulse period 측정
      • 펄스폭 주기 측정을 위한 회로 구성 예

        이 예는 펄스 신호의 주기 측정기술 이해하기 위한 예 이다.

      • Timer counter를 이용한 Pulse Width 측정 예: pulse-period-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)은 서로 다를 수 있다.

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

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

        • PC에서 모니터 프로그램(예: OC-Console, Tera Term)을 설치(이미 설치되어 있는 경우에는 실행만 하면됨)하고 실행 한다.
        • 모니터 프로그램에서 USB --> UART(RS232) 변환 모듈의 Serial Port를 확인하고 필요한 설정(Serial Port와 Baudrate(115200) 등을 설정)을 한다.
        • 실험
          • 프로그램이 실행되면 측정된 펄스 주기가 PC 모니터의 출력된다.
          • GPIO21 버튼을 누르면 펄스 주기가 증가하고, GPIO22 버튼을 누르면 펄스 주기가 감소한다.
          • 펄스 주기에 따라 LED가 점멸한다.

  • Raspberry Pi Pico Timer - C 관련 페이지 보기