Zynq SoC Training – Hardware Timers

Acknowledgement (Korean)
아래의 글은 Ali Aljaani가 운영하는 블로그인 embedded centric의 “Zynq SoC Training”을 번역한 문서입니다. 한글 번역 및 공개를 허용한 Ali Aljaani에게 감사의 말을 전합니다.

Acknowledgement (English)
This post is a translated version of “Zynq SoC training” in embedded centric. Thank you Ali Aljaani for allowing me to translate nice posts. I’m Taekyung Heo, and I translated this post into Korean.

Contact information (Author)
Ali Aljaani’s blog: http://embeddedcentric.com/
Ali Aljaani’s mail: alialjaani@embeddedcentric.com
Ali Aljaani’s LinkedIn: https://www.linkedin.com/in/ali-aljaani-a7130099
Ali Aljaani’s github: https://github.com/ama142


이번 실습에서는 Zynq SoC에서 사용 가능한 다양한 하드웨어 타이머를 알아보고, 각각의 알맞은 용도를 알아볼 것이다. PL-side에 AXI-Timer를 추가해서 실습할 것이다. 이 타이머를 사용해서 매 초마다 주기적으로 인터럽트를 발생시키고, 디지털 시계를 설계하고자 한다.

lab5-design-flow


Lab5 Design Flow

lab5-block-diagram


Lab5 Block Diagram

lab5-board-interface


Lab5 Board Interface

정확한 타이밍은 거의 대부분의 임베디드 시스템에서 매우 중요하다. 하드웨어 타이머가 이같은 서비스를 제공한다. Zynq 칩들은 다양한 종류의 타이머를 제공한다: Cortex-A9 프로세서는 내부에 32-bit private 타이머와 32-bit watchdog 타이머를 갖고 있다. 반면에, 프로세서 시스템 수준에서는 한 개의 24-bit System Watch Dog Timer (SWDT)와 두 개의 16-bit Triple Timer/Counters(TTC)가 있다. SWDT는 일반적으로 심각한 시스템 결험 이벤트가 발생했음을 알리기 위해 쓰인다. 예를 들어 CLK PS 오류 또는 자동화된 시스템 리셋에 사용될 수 있다. 반면에 TTC는 더 다양한 목적으로 사용될 수 있다. 예를 들어, PWM 생성, waveform 생성 등에 사용될 수 있다. 스케쥴러는 미리 정해진 카운터 값에 따라 다른 인터럽트를 발생시킨다.

hardware-timers-on-the-zynq


Hardware Timers on the Zynq

zynq-architecture-with-hardware-timers-highlighted


Zynq Architecture with hardware timers highlighted

목표
1. Zynq에서 사용할 수 있는 다양한 하드웨어 타이머 소개
2. AXI-Timer에 대해 자세히 알아보고, 매 초마다 인터럽트를 주기적으로 발생시키기
3. 다양한 인터럽트 소스를 활용해 인터럽트 기반의 시스템을 설계하기
4. 논리 연산을 위해 Vivado 기본 논리 블록을 사용하기
5. 이미 설계한 시스템의 기능을 확장하기

실습 단계
A. Lab4의 실습 디렉토리를 복사
1. “C:\embeddedcentric” 디렉토리에 새로운 폴더를 생성하고, 이름을 “lab5″로 한다.

create-a-new-folder


Create a new folder

2. 이전 실습의 디렉토리인 “C:\embeddedcentric\lab4”를 연다. “lab4.sdk”를 제외한 모든 파일을 복사한다 (Ctrl 키를 사용해 여러 파일을 선택한다). Note: lab4 파일들을 갖고 있지 않으면, 내 GitHub 페이지에서 받을 수 있다.

copy-lab4-content-except-sdk-project


Copy Lab4 content (EXCEPT SDK Project)

3. 복사한 것을 앞서 생성한 “C:\embeddedcentric\lab5” 디렉토리에 붙여넣는다.

moving-the-content-of-lab4


Moving the content of lab4

4. “lab4.xpr”을 더블 클릭해 Vivado를 연다. IMPORTANT NOTE: Vivado 프로젝트 파일의 이름을 수정하면 안 된다. 다섯 번째 실습이지만 “lab4.xpr”로 유지해야 한다. 이 파일의 이름을 변경하는 것은 문제를 유발할 수 있다.

이로써 이전 실습 파일을 새 디렉토리에 복사한 뒤에 Vivado를 열었다.

B. AXI-Timer를 추가하고 설정하기
1. Sources 창에서 zynq_interrupt_system_i.bd를 더블 클릭하면 블록 다이어그램이 뜬다.

open-the-block-diagram


Open the Block Diagram

2. 다이어그램 창에서 우클릭하고 Add IP를 선택한다. 탐색창에 “timer”를 입력한다. AXI-Timer를 선택하고 더블 클릭해 이를 블록 다이어그램에 추가한다.

add-axi-timer


Add AXI-Timer

3. 다이어그램 창의 좌측 상단에 Designer Assistance를 사용할 수 있다는 알림이 뜬다. Run Connection Automation을 클릭한다. Run Connection Automation 창이 뜰 것이고, 기본 옵션으로 둔 다음에 OK를 클릭한다.

run-connection-automation-axi-timer


Run Connection Automation-AXI Timer

AXI 타이머를 구동하는 클럭은 50MHz의 FCLK_CLK0이다. 이는 PS의 Re-customize IP ->Clock Configuration->PL Fabric Clocks->FCLK_CLK0에서 설정할 수 있다.

pl-fabric-clock1


PL Fabric Clock

FCLK_CLK0는 타이밍 요구 사항에 맞추어 수정할 수 있다. AXI-Timer를 구동하는 진동수가 타이머의 해상도와 오버플로우 없이 시간을 측정할 수 있는 길이를 결정한다. 진동수는 0.1부터 250MHz 사이에서 선택 가능하다. 클럭 소스는 필요에 따라 PL Fabric Clocks에서 최대 네 개까지 선택 가능하다.

4. AXI Timer는 인터럽트 포트를 제공하며, 이를 사용하기 위해서는 Zynq PS와의 연결이 필요하다. 하지만 우리는 이미 GPIO 인터럽트를 PS 인터럽트 포트에 연결해두었다 (이전 실습에서 완료함). 이 포트는 사실상 16개의 인터럽트까지 지원할 수 있는 공유 인터럽트 포트이다. 그리고 버스를 통해 여러 개의 인터럽트를 받을 수 있다. 따라서 GPIO와 AXI-Timer 인터럽트 모두를 연결하기 위한 추가 IP 블록이 필요하다. 다이어그램 창에서 우클릭하고 Add IP을 선택한다. 탐색창에서 “concat”를 입력하고 더블클릭해 Concat IP를 추가한다. “concat”은 concatenation의 약어이다. 이를 사용해 독립적인 신호 또는 개별 벡터를 합쳐 더 큰 신호 또는 벡터를 생성할 수 있다.

add-concat-ip


Add Concat IP

5. Zynq PS에서 IRQ_F2P[0:0] 연결을 제거한다. 해당 연결을 클릭하고 DELETE를 눌러 제거할 수 있다. 대신에 Concat 블록의 출력을 IRQ_F2P[0:0]에 연결한다. GPIO로부터의 인터럽트 요청을 Concat의 첫 번째 입력 포트에 연결하고, 타이머로부터의 인터럽트를 Concat의 두 번째 입력 포트에 연결한다. 이로써 2-bit 크기의 버스를 생성하고 PS에 인터럽트 신호를 전달할 수 있다. 다이어그램 창에서 임의의 빈 지점을 우클릭하고 Regenerate layout을 클릭한다. 그러면 블록 다이어그램은 다음과 같이 보인다:

block-diagram-after-concatenating-the-interrupts-signals


Block Diagram after concatenating the interrupts signals

IRQ_F2P[0:0]는 PL에서 PS로 가는 16-bit 공유 인터럽트 라인이다 (여기서 공유라 함은 두 개의 CPU 모두에서 사용 가능하다는 것이다). 여기서 여러 개의 인터럽트 소스를 사용하고 있기 때문에, 인터럽트는 본질적으로 비동기적인 이벤트이다 (언제나 발생할 수 있다). 이는 동시에 두 개 이상의 인터럽트가 발생할 수 있다는 것을 의미한다. 이 문제는 우선순위 부여를 통해 해결 가능하다. 우선순위 부여는 여러 개의 인터럽트가 발생했을 때, 우선순위에 기반하여 어떤 인터럽트를 먼저 처리할 것인지를 결정해준다.

Zynq에서 우선순위 부여는 인터럽트 신호 중 무엇을 높은 위치의 비트에 위치시키는지에 따라 결정된다. MSB(Most Significant Bit)은 가장 높은 우선순위를 부여받고, LSB(Least Significant Bit)는 가장 낮은 우선순위를 부여받는다. 따라서, 이 설계에서는 In1[0:0]에 연결된 타이머의 인터럽트가 GPIO 인터럽트보다 더 높은 우선순위를 부여받는다.

C. Bitstream 생성

Flow NavigatorProgram and Debug 섹션에서 Generate Bitstream을 클릭한다. 대화 상자가 수정 사항을 반영할 것인지 물어보면 Save을 클릭한다.

generating-bitstream1


Generating Bitstream

Bitstream 생성은 컴퓨터의 사양에 따라 어느 정도 시간이 걸릴 수 있다. Bitstream 생성 이후에 대화 상자에서 View Reports을 선택하고 OK를 클릭한다.

D. 하드웨어 설계를 SDK에 내보내기
1. File > Export > Export Hardware를 클릭한다. 반드시 Include bitstream을 선택하도록 한다.

export-hardware-to-sdk


Export Hardware to SDK

2. File>Launch SDK을 선택한다. Launch SDK 대화창이 열리면 기본 설정을 그대로 두고 OK를 클릭한다. 설계에 관련된 모든 하드웨어 파일이 SDK에 내보내기 되었고, 이제 우리는 소프트웨어를 개발하면 된다.

이제 시스템에 대한 하드웨어 설정은 마쳤다. Vivado를 닫아도 된다.

E. SDK에서 작업하기
1. SDK에서 File > New > Application Project를 선택한다.
2. Application Project 창에서 다음과 같이 설정값을 입력한다.

new-standalone-c-project-real_time_clock


New Standalone C Project – real_time_clock

다음 창에서 Empty Application을 선택하고 Finish를 클릭한다. 이는 BSP와 관련된 드라이버를 컴파일할 것이다.

3. real_time_clock 디렉토리를 확장하고, src 디렉토리를 우클릭해 New->Source File을 선택한다.

new-c-source-file-lab5


New C Source File – lab5.c

4. 다음 창이 뜨면 소스 파일 이름에 “lab5.c”를 입력하고 Finish를 클릭한다. 이는 src 디렉토리에 빈 C 파일을 생성할 것이다.

lab5-c-empty-source-file-created-in-sdk


lab5.c empty source file created in SDK

5. SDK에서 lab5.c를 열고, lab5.c의 내용을 붙여넣는다(내 GitHub 페이지에서 받을 수 있다). 이후 Save을 클릭하거나 Ctrl+S를 눌러 저장한다. 이를 통해 lab45 어플리케이션과 BSP를 컴파일할 수 있다. 실행 파일은 ARM 프로세서의 PS side에서 실행된다.

lab5.clab4.c의 확장된 버전이다. 추가된 부분은 lab4.c위에 주석으로 기록해두었다. 추가된 부분은 AXI-Timer를 위한 인터럽트 핸들러 (ISR)와 인터럽트 설정 함수이다.

lab5-additions-on-lab4-c-code


Lab5 additions on Lab4 C code

main() 함수는 GPIO를 초기화하고 입력 방향을 설정한다. 그리고 AXI-Timer를 초기화하고 설정한다. AXI-Timer를 counting up 타이머로 설정하고, TMR_LOAD를 인자로 주어 매 초 인터럽트를 발생시키도록 한다. 그 이후에 IntcInitFunction()을 호출해 GIC 인터럽트 컨트롤러를 초기화하고, GPIO와 AXI-Timer 인터럽트 핸들러를 등록한다. 이를 통해 인터럽트가 발생했을 때 ISR이 불려질 수 있도록 한다. IntcInitFunction()InterruptSystemSetup() 함수를 호출해 GIC 인터럽트 핸들러를 등록한다.

main() 함수는 그리고 무한 루프에 들어간다 (241~243번째 줄). 이 무한 루프에서 프로세서는 루프를 돌 뿐, 특별한 것은 하지 않는다. AXI-Timer 또는 푸쉬 버튼에 의해 인터럽트가 발생하면 프로세서는 main() 함수의 실행을 잠시 멈추고, 인터럽트 소스에 적합한 인터럽트 서비스 핸들러를 실행한다. 두 개의 시나리오가 가능하다:

첫 번째 시나리오, 푸쉬 버튼이 눌린다: BTN_Intr_Handler()가 호출된다. 이는 GPIO의 데이터 레지스터를 읽어 세 개의 푸쉬 버튼 중에 무엇이 눌렸는지 확인한다. BNTC가 눌렸으면 시계가 초기화된다. BTNL이 눌렸으면 시간 자리를 증가시킨다. BTNR이 눌렸으면 분 자리를 증가시킨다.
두 번째 시나리오, AXI-Timer 오버플로우: TMR_Intr_Handler()가 호출된다. 이는 초를 증가시키고 시간을 OLED에 출력한다.

lab5-c-code


Lab5 C Code

F. Bitstream을 다운로드하고 어플리케이션을 실행하기 (하드웨어 검증)
1. Xilinx Tools-> Program FPGA를 선택해 Bitstream을 받을 수 있다 (몇 초가 소요될 수 있다).

program-fpga


Program FPGAa

2. real_time_clock 디렉토리를 선택하고 Run As-> Launch on Hardware (GDB)을 클릭해 real_time_clock 어플리케이션을 ARM 프로세서에서 실행할 수 있다.

run-application-lab5


Run Application lab5.c

어플리케이션이 로드되면 시간이 OLED에 표시되는 것을 확인할 수 있다.

output.jpg


Real Time Clock

우측 버튼을 눌러 분을, 좌측 버튼을 눌러 시를 증가시킬 수 있으며, 가운데 버튼을 눌러 시간을 리셋할 수 있다.


이로써 다섯 번째 실습인 Hardware Timers를 마친다. 이번 실습에 대한 해답은 여기에 있다.


Advertisements
Tagged with: , , , , , , , , , , , , , , , , , , , , ,
Posted in FPGA

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

누적 방문자 수
  • 93,200 hits
%d bloggers like this: