GPIF

출처 : http://muosys.egloos.com/125743

 

오늘은 GPIF를 가지고 데이터를 전송하기 위한 준비 학습을 해 보자.

본론에 들어가기 앞서, 어제 강의에서 설명하지 않은 parallel.exe의 소스 코드를 살짜쿵 건드려주고 넘어가자.

Parallel.exe의 기본적인 골격은 MFC 위저드로 만든 Dialog base 어플리케이션이다.

거기에 버튼과 에디트박스 몇 개를 리소스에 추가하고
CParallelDlg에 몇 개의 멤버변수와 다음의 멤버함수를 추가한 것이다.
VOID SendData(PCHAR pBuffer, DWORD dwBufLen)
VOID OnButtonTransfer()
VOID OnButtonFile()
BOOL GetPreviousFile( CString &FileName )
VOID SaveFileName( CString FileName )
VOID OnParallelButtonInit()
그리고 위저드에 의해 생성된 OnInitDialog()함수의 끝부분에 몇 줄의 코드를 추가했다.

MFC 프로그램을 할 줄 아는 행자들이야 따로 설명 안 해도 소스코드 보고, 개조하는데 별 어려움이 없겠지만, 그렇지 않은 행자들을 위해 간단히 설명하겠다.
뭐 그렇다고 MFC 프로그래밍에 대한 개괄적 설명까지는 할 시간이 없고, ( 관심 있으시면 MFC책 사서 보시라. ) 본좌가 만든 함수의 기능에 대한 설명만 언급하겠다.
WinAPI나 클래스함수에 대한 설명은 MSDN Library를 참조하시라.

VOID SendData(PCHAR pBuffer, DWORD dwBufLen)
페러렐 포트를 통해 데이터를 전송하는 함수이다. 실제로 일을 하는 부분이다. 프로토콜을 손보기 위해서는 이 부분만 건들이면 된다.

VOID OnButtonTransfer()
“Transfer” 버튼이 눌리면 호출되는 함수이다.

VOID OnButtonFile()
“File” 버튼이 눌리면 호출되는 함수이다.

BOOL GetPreviousFile( CString &FileName )
프로그램 시작시 레지스트리에 저장되어 있던 이전 열었던 파일의 이름을 얻기 위한 함수이다.

VOID SaveFileName( CString FileName )
레지스트리에 열어본 파일이름을 저장하기 위한 함수이다.

VOID OnParallelButtonInit()
페러렐 포트 레지스터의 값을 초기값(?)으로 세팅해 주는 함수이다.

BOOL OnInitDialog()
프로그램 시작 시 호출되는 함수이다. 프로그램 초기화 시 필요한 일들은 여기에서 처리해라.
아래는 SendData(..)함수에 대한 설명이다.

clip_image001

본좌처럼 페러렐 포트를 이용하지 않고, 다른 마이컴을 물려서 테스트할 행자들은 위 플로우챠트를 참고해서 펌웨어를 코딩하시라

Cypress FX2의 GPIF(General Programmable Interface)는 이미 설명한 대로 USB 2.0의 대역폭에 비해 8051코어가 너무 느리게 동작하기 때문에 이것을 대신해 외부에서 들어오는 데이터를 빠르게 FIFO에 채우고(또는 USB를 통해 전송 받은 FIFO의 데이터를 외부로 내보내고),  패킷을 날리는 일을 해주는 State Machine이다.

이것도 일종의 프로세서이니 만큼 입력과 출력이 있고, 우리가 프로그램을 해 줘야 동작을 한다.

GPIF를 동작시키기 위해 어떻게 프로그램을 하느냐?
Cypress 사이트에 가서 GPIF Designer를 다운받아 설치하시라.

설치된 GPIF Designer를 가지고 GPIF엔진이 어떻게 동작 할지를 프로그래밍 할 수 있다.
물론 GPIF에 관련된 레지스트리에 일일이 값을 써주어서 GPIF를 프로그래밍 할 수도 있지만, 쉬운 길 놔 두고 뭐하러 사서 고생하남?

clip_image002

그림에서 볼 수 있듯이(T.R.M. Page 10-2) GPIF는
외부로부터의 컨트롤 신호 입력을 받을 수 있는 여섯개의 핀(RDY[5:0])
외부로 컨트롤 신호를 줄 수 있는 여섯개의 핀(CTL[5:0]),
8bit 혹은 16bit로 세팅할 수 있는 데이터 버스(FD[15:0]),
그리고 외부의 장치(ex. 메모리)에 주소를 할당해 줄 수 있는 9bit의 어드레스 라인(GPIFADR[8:0])을 가지고 있다.

그리고 GPIF엔진에 먹일 클럭은 외부클럭(5~48MHz) 또는 30/48MHz의 내부클럭 중에 선택 할 수 있다.
먹인 클럭에 따라 동작하는 Sync모드로도 동작할 수도 있지만, 클럭에 상관없이 Async모드로도 동작하게 할 수도 있다.

이전에 언급한 바와 같이 GPIF엔진은 7개의 상태(state)를 가질 수 있는데, GSTATE[2:0]은 GPIF엔진이 지금 어떤 state에 있는지를 나타내주는 출력 핀이다.
디버깅 용도 이외에는 사용할 일이 없는 핀이다.

나머지 입출력들에 대해서는 예제를 통해 차차 설명하도록 하겠다.

그림 중간에 Waveform Descriptors라고 네 개의 Descriptor가 있는데,
이 Descriptor에 GPIF을 통제할 프로그램을 넣어주어야 한다.
Waveform Descriptor는 실제로는 관련 레지스터에 들어갈 값들이다.

GPIF Designer를 써서 이 Waveform Descriptor를 쉽게 생성할 수 있다.
우리가 GPIF를 프로그램 하기 위해 해야 할 일은 GPIF Designer를 써서 Waveform Descriptor를 작성한 후에 gpif.c파일을 생성하고, 이 파일을 프로젝트에 포함시킨 후 TD_Init()에서 GPIF_Init() 함수를 호출해 주는 일이다.
간단하지 않은가?

우리가 쓰는 56핀 Cypress FX2에서는 CTL핀이 세개, RDY핀이 두개가 있고, GPIFADDR핀은 아예 없다.
하지만 이 핀들만 가지고도 웬만한 작업은 거의 다 처리 할 수 있다.

GPIF Designer를 설치한 행자들은 C:\Program Files\Cypress\GPIF Designer 폴더에 가면 예제들이 있으니 함 구경해 보시라.
GPIF Designer 프로그램을 실행한 후, xxx.gpf 파일을 열면 예제가 제공하는 waveform을 볼 수 있다.
거기의 waveform처럼 우리가 마우스를 클릭 클릭해서 파형을 그려주고, 메뉴의 Tool->Export to gpif.c file 을 눌러주면 gpif.c파일이 생성된다.

clip_image003

오늘은 GPIF를 이용하여 BULK IN 예제와 똑같은 일을 하도록 예제를 꾸며보자.

예제는 앞서 BULK IN 예제에서와 마찬가지로 UniHigh v1.0에서 필요 없는 DR_VendorCmnd()함수 내부를 비우고 이를 기본으로 하여 살을 덧붙였다.

UniHigh v1.7
(실행 전에 Waveform 작성하기 앞부분 참조.)

회로는 다음과 같이 꾸몄다.
이전에는 Port A의 핀들을 사용했지만,
이번에는 GPIF를 사용하기 때문에 RDY0(STROBE), RDY1(SELECT), CTL0(ACK)핀을 사용한다.

clip_image005

clip_image006

GPIF가 State Machine이라고 하였으므로, GPIF Designer를 써서 WaveForm을 만들기 전에 먼저 State Diagram을 그려보는 것이 나중에 Waveform을 만들 때 헛갈리는 것을 줄여준다.

clip_image007

일단 완성된 Diagram은 다음과 같다.
(그림이 잘 안보이면, 그림을 클릭해서 크게 보거나, 다운로드한 후 보시라.)

clip_image009

복잡해 보이지만 하나하나 따라가다 보면 그리 복잡하지도 않다.

첫 번째,
일단 GPIF engine을 처음 구동시키는 것은 8051 펌웨어이다.
GPIF 엔진이 일단 일을 시작하면 8051은 빠지고, 전적으로 GPIF가 데이터의 흐름을 관리하게 된다. 물론 8051이 중간 중간 끼어들어 데이터를 첨삭하거나 수정하는 등 필요한 작업을 할 수도 있다.
GPIF가 시작되면 GPIF state는 Idle ->S0로 간다.

clip_image011

두 번째,
본좌의 허접탱탱구리 프로토콜에 의하면 Parallel 포트의 SELECT(17번 핀)가 LOW로 떨어지는 것은 곧 데이터 전송이 시작될 것을 의미하므로, 다음 state로 넘어가서 데이터를 전송 받는 절차를 시작하고, 그렇지 않다면 그 state에서 SELECT가 LOW로 떨어질 때까지 기다린다.

clip_image012

세 번째,
S1 state는 일단 없는 것으로 생각하고, SELECT가 LOW로 떨어지면 S0에서 S2로 넘어가는 것으로 생각하자.

clip_image014

네 번째,
S2상태에서 STROBE(1번 핀)가 LOW로 떨어지면, 이는 Parallel 포트의 데이터라인에 데이터가 실려있다는 것을 알려주는 신호이므로 이를 받기 위해 S3으로 상태를 바꾼다.
그런데, 만일 우리가 FIFO에 받은 데이터를 USB를 통해 호스트로 다시 전송하는 속도가 패러렐 포트에서 데이터를 받는 속도보다 느려서(그럴 가능성은 적지만.)
FIFO가 꽉 차 있을 경우에는 데이터를 더 받으면 안되므로, FIFO Full Flag가 0이 될 때까지 기다린다.

clip_image016

다섯 번째,
S3 state에서는 FD[7:0]을 통해 받은 데이터를 FIFO에 써넣고, 데이터를 잘 받았다는 것을 알리기 위해 ACK(10번 핀)를 HIGH로 세팅한다.
“Parallel” 어플리케이션은 ACK가 HIGH가 되면 자신도 한 바이트에 대한 데이터 전송절차를 마무리하는 뜻으로 STROBE를 HIGH로 되돌린다.

clip_image018

여섯 번째,
STROBE가 HIGH가 되면 ACK를 원래대로 LOW로 되돌린다.

clip_image020

일곱 번째,
SLEECT가 HIGH라면 데이터 전송이 다 끝난 것이므로, IDLE상태로 가서 GPIF transaction을 마무리하고, 아니라면 S1으로 간다.

clip_image022

여덟 번째,
S1에서는 SELECT가 HIGH가 될 때, Idle상태로 간다

아~!!!!

뭔가 설명해 놓고도, 본좌가 뭔 소리를 지껄였는지 잘 모르겠다.
정리해서 낼 더 쉬운 말과 그림으로 풀어드릴테니 지둘리시라.

이넘의 GPIF는 할때마다 매번 헷갈린다.
한번 헷갈리면 디버깅하기도 영 엿같은 일이 된다.
따라서, GPIF에서는 시간을 좀 더 들이더라도 확실히 개념 잡고 넘어가도록 해보자.
또 그만치 중요하다.

오늘 예제는 저번 BULK IN 예제와 동일한 방법으로 테스트하면 된다.
* BULK IN 강좌에 덧글 단 대로 페러렐 포트의 CMOS setup을 ECP로 놓고 하시라.

어제 왜 그렇게 본좌의 머리가 뒤죽박죽 정리가 안되었었는지 곰곰히 생각해 보니 설명한 분량은 많은데, 그걸 짧게 줄여 설명하려고 하다 보니 두뇌회로에 데드락이 걸려버렸던 거시다.

GPIF도 막상 알고 나면 별 거 없는데, 막상 설명하려니 이것 저것 언급하고 넘어가야 할게 적지 않다.
이젠 체념하고 강좌가 길어지더라도 설명할 껀 다 설명하고 가야겠다.
에효~.

느린 처리속도를 가진 8051코어를 대신해서 데이터의 흐름을 관리해 주는 것이 GPIF이므로 데이터의 대역폭이 중요하지 않은 어플리케이션을 디자인하려고 하는 행자들은 맘편히 GPIF는 생까고 넘어가시라.
예를 들어 모터제어를 GPIF를 통해 하겠다 라고 생각한다면 그건 돼지발에 꽃신 신기는 격이다.

그렇지 않고, 내가 만들 뭐시기에는 대역폭이 너므~너므~ 중요해. 라고 생각하는 행자들은 3단 콤보 로우킥이 들어와도 GPIF는 맞고 넘어가야 할 거시다.

오늘은 GPIF Designer를 사용해서 Waveform을 만들기 전까지의 절차를 알아보자.

GPIF Designer를 시작하면 이 프로그램을 종료하기 전에 편집했던 마지막 gpf 파일이 로딩되는데, 우리는 우리의 목적에 맞는 새 gpf파일을 한번 만들어보자.

GPIF Designer를 실행하고, 메뉴의 File -> New를 선택하면 다음과 같은 창이 뜬다.
UniHigh보드의 칩은 Cypress의 56pin FX2( CY7C68013 )이므로 CY FX2(56 pin) 항목을 선택해 준다.

clip_image023

그럼 다음과 같은 화면이 뜰 것이다.
일단 이 상태에서 File -> Save As를 눌러 parallel.gpf를 파일 이름으로 하여 원하는 위치에 저장하자.

clip_image024

오른쪽에 Un-named라고 이름이 붙은 박스에 커서를 위치시키고 오른 버튼을 클릭하면 다음과 같은 박스가 뜬다.
거따가 적절한 이름을 써 넣자.
이 이름은 Waveform 디자인에는 아무 영향이 없는, 그저 우리에게 보여지기 위한 이름이다.

clip_image025

우리가 사용할 데이터 버스의 폭은 8bit이므로 이를 세팅해 주어야 한다.
gpf 프로젝트를 생성할 때는 디폴트로 16bit로 되어 있으므로 아래쪽 데이터버스(Data[15:8])에 대고 마우스 오른 버튼을 클릭하면 나타나는 “Use This Bus” 버튼을 클릭해주면 체크가 해제된다.
T.R.M. p.1-19에 나와 있듯이 GPIF모드로 동작할 때는 Port B가 Data[7:0]으로 사용되므로 여기에 우리가 직접 만든 페러렐 포트의 2번~9번 핀까지를 물려주면 되겠다.

clip_image026

아래 그림의 빨간 박스부분을 누르면 Clock property라는 대화상자가 뜬다.
이 대화상자는 IFCFG라는 레지스터를 세팅해 주기 위한 것으로, IFCLK가 Internal로 되어 있으면 GPIF에 공급되는 클럭을 30/48 MHz로 세팅할 수 있고, IFCLK가 External이라면 IFCLK핀으로부터 들어오는 5~48MHz사이의 클럭에 맞취 GPIF가 동작하게 된다.
옵션으로 Clock을 반전시켜 사용할 수 있는데, T.R.M. p.10-9의 아랫쪽 그림처럼 Signal Setup Time을 충분히 갖기 위한 용도로 사용할 수 있다.

clip_image027

우리는 Async모드로 GPIF를 동작시킬 것이므로 Clock세팅은 48MHz에 맞추어 놓자.
IFCLK output은 우리가 쓸일이 없으므로 Disable시키자.
Enable 시켜서 IFCLK 핀으로 48MHz의 클럭이 출력되더라도 별 상관은 없다.

clip_image028

Synchronous모드에서 동작한다는 것은 Clock에 맞추어 데이터와 Signal이 Sampling되고, Control 신호가 asserting되는 것을 의미함은 잘 알고 계시리라.
반면에 Asynchronous 모드로 동작한다는 것은 클럭 입력 없이 Signal의 Transition에 맞추어 동작하는 것을 의미하지만, GPIF는 Async모드에서도 내부적으로는 클럭(30/48MHz)에 동기되어 동작한다.
예를 들어 S1 상태에서 S2로 넘어가기 위한 조건이 READY0핀이 Low->High로 되는 것이라면, 이상적으로는 READY0핀이 High가 되자마자 S2 상태가 되어야 하지만, FX2에서는 (48MHz 일때) 최대 24 nSec까지 상태변화가 지연될 수 있다

RDY선 또는 글자 근처에 대고 오른버튼을 클릭하면 다음과 같은 대화상자가 나타난다.
GPIF 입력핀의 이름을 우리가 정한 이름으로 바꾸어 주자.
(이것도 역시 우리가 보기 편하게 하기 위함이며, Waveform과는 별 관계 없다.)

clip_image029

빨간 박스로 표시한 곳에 체크를 하면 GPIF가 Sync모드로 동작하게 된다.
우리는 Async모드로 동작하므로 그냥 놔두자.

clip_image030

마찬가지로 CTL에 오른버튼 클릭하면 다음과 같은 대화 창이 뜨는데, 우리가 필요한 CTL핀은 하나 뿐이므로, 나머지는 체크를 해제하고, 그 CTL0의 이름을 ACK로 바꾸어 주자. (마찬가지로 이름은 우리가 보기 위한 것이다.)

clip_image031

GPIF Designer의 Block Diagram 탭 옆에는 이름이 Single Read/Write, FIFO Read/Write인 다른 탭들이 있는데, Single Read/Write는 GPIF를 이용해서 FIFO에 한 바이트(워드)씩을 읽거나 쓰기 위한 waveform을 위한 자리로 Cypress가 마련해 놓은 것이며, FIFO Read/Write는 한번에, 즉 GPIF가 시작되어 그 사이클을 끝낼 때까지 여러 바이트(워드)의 데이터를 읽거나 쓰기 위해 마련해 놓은 곳이다.

한 바이트나 워드를 위해 왜 굳이 GPIF를 쓰는지 궁금해 하실 행자들을 위해 설명하자면 바로 연습용도이다.
T.R.M.에서는 GPIF를 이용해 한 바이트나 워드를 읽고 쓰기에 성공한 후에, FIFO Read/Write을 시도하라고 일러주고 있지만, 본좌는 대개 무시하고 막바로 FIFO Read/Write을 시도한다.

탭들의 이름이 미리 저렇게 붙어 있지만, 그 이름대로 그 자리에 꼭 그 일을 하는 waveform을 넣어야 하는 것은 아니다.
첫 번째 탭(첫 번째 waveform)에 FIFO Write를 위한 waveform을 넣어도 되며, 모든 탭에 FIFO Read를 위한 waveform을 넣어도 된다.
하지만 관행대로 탭들에 붙은 제목대로 waveform을 넣기를 권장한다.

우리는 FIFO Read를 위한 waveform만 있으면 되므로, 나머지 탭의 제목은 다 unused로 바꾸어 주자.
해당 탭을 활성화 한 뒤 탭 제목부분에서 마우스 오른클릭을 하면 Tab Label을 바꿀 수 있는 메뉴가 나온다.

clip_image032

* FIFO Read/Write이라는 용어에서 Read나 Write냐 하는 기준은 FX2입장에서 봤을때이다.
즉, FX2가 데이터버스( FD[15:0] )를 통해 데이터를 읽을때는 (FIFO) Read, 쓸때는 (FIFO) Write이다.

clip_image033

이제 waveform을 그리면 된다.
Save를 눌러 이제까지 설정한 내용 저장하시는거 잊지마시라.

Advertisements

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중