Control Endpoint의 DATA stage 활용

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

 

먼저 UniHigh Module의 VCC, GND마킹이 반대로 인쇄되었다는 비보를 행자들에게 알려야 하겠다.

clip_image001

회로도의 핀 OUT 그림이 옳고, UniHigh PCB 중간부분 양쪽 가장자리에 인쇄된 VCC, GND는 반대로 인쇄되어 있으니, 추후 혼란을 방지하기 위해 행자들은 인쇄된 글자를 칼로 살살 긁어 지워 버리자.
(그리고 빨강 메직펜과 까망 메직펜이 있으면 회로도를 보면서 VCC/GND 옆에 각각의 색으로 점을 찍어두면 더 훌륭하리라.)

clip_image003

LED 가 켜지고 꺼지는 비트 설정이 반대네?
본좌. 의아해 하면서 기냥 넘어 갔드렜는데, 역쉬나. 뭔가 잘못 되어가고 있던 거시어따.

결과적으로 이틀 전에 보여준 LED 회로도도 반대로 되어야 한다.
본좌 구라대왕이 되어 버렸다.
미얀타.

clip_image004

흠.
오늘도 어제 그제에 이어 Default Control Endpoint를 통해 통신하는 법이다.
Endpoint 0를 통해 8바이트 이상의 데이터를 전송 해야 할 필요가 있을 때는 어이할까?
두 번에 나눠 보내면 된다.
물론 뻥~이다. ㅋㅋㅋ

8 바이트 이상의 데이터를 전송할 필요가 있을 때에는 SETUP stage다음에 DATA stage를 딸려 보내면 된다.

EZ-USB Control Panel에서는 “Dir” 항목을 0 OUT으로 놓고 그 옆의 에디트 박스에 자신이 원하는 16진수 데이터를 써 넣으면 어플리케이션과 드라이버가 알아서 SETUP stage의 Length필드에 데이터의 길이를 써 넣고, DATA stage에 실 데이터를 채워서 디바이스로 보낸다.

만일 우리가 Cypress에서 제공하는 EZ-USB Control Panel 어플리케이션과 ezusb.sys 드라이버 대신에 우리가 만든 어플리케이션과 드라이버를 쓴다면, 어플리케이션 개발자와 드라이버 개발자가 서로 인터페이스를 상의하여 동일한 동작이 일어날 수 있도록 코딩을 해 주어야 한다.

T.R.M.의 P.1-23에 나온 것 처럼 EP 0의 버퍼 사이즈는 64byte 이므로 64바이트만 보낼 수 있느냐 하면 OUT transfer에서는 그렇다. 가 정답이고 IN transfer에서는 64바이트 짜리 DATA stage를 연달아 이어 보낼 수도 있으므로 아니다. 가 정답이다.

이 엔드포인트를 통해 우리가 주고자 하는 데이터를 호스트로 보낼 수도 있으므로, Default Control Endpoint만 제대로 다루어도 오가는 데이터량이 많지 않은 웬만한 제어는 다 될 거 같은 예감이 들지 않는가?

오늘은 DATA stage를 이용해서 데이터를 보내는 펌웨어를 맹글어 보자.

DATA stage에 아래와 같은 데이터를 보내면
00 50 00 50 01 00 01 00 02 00 02 00 03 00 03 00 04 00 04 00

clip_image006

이를 4바이트씩 끊어서
첫번째 워드(2바이트)는 LED가 켜지는 시간(ms)
두번째 워드(2바이트)는 LED가 꺼지는 시간(ms).
(반복)…
요렇게 동작하도록 코딩을 해 보자.

본좌의 소스에는 예외처리를 넣지 않았으므로 행자들이 데이터를 잘못 입력한 경우에 어떤 일이 일어날지는 책임 못진다.
최악의 경우 지구가 멸망할 것이다.
조심하시라.

DATA stage를 사용하는 EP 0의 OUT transfer에서는 EP0BCL에 아무 숫자나 써주어야 우리는 비로소 EP0BUF[]의 데이터를 활용할 수 있게 되며, FX2는 호스트에 데이터를 잘 받았다고 ACK를 날릴 수 있게 된다.

설명하나 마나 감으로 딱 알 수 있듯이 EP0BUF[]는 DATA Stage의 데이터가 들어와 앉는 자리이다.
UniHigh1.2.zip

계속해서 Data stage를 가지고 데이터를 호스트로 보내는 방법을 익혀보자.

사실 이 방법은 이미 우리의 코드에 들어 있다.
Fw.c의 SetupCommand()함수에 보면 case SC_GET_DESCRIPTOR:와 case SC_GET_STATUS:가 디바이스가 Default Control Transfer를 수행하는 중에 Data Stage를 통해 데이터를 호스트로 전송하는 예이다.

우리가 desc.a51 파일을 작성하고 펌웨어를 빌드한 후에 UniHigh에 다운로딩 하면, FX2의 메모리 어딘가에 Descriptor들이 들어가 있을 것이다.
Descriptor들이 들어가 있는 메모리 주소들을 가리키는 인덱스가 각각 pDeviceDscr, pDeviceQualDscr, pConfigDscr, …인데, 이 주소들 중에 하나를 SUDPTRH/L 레지스터에 써 넣으면 SUDPTRH/L의 메모리 주소가 가리키는 곳의 데이터를 FX가 알아서 Data Stage에 실어 보내게 된다.

만약 보낼 데이터가 64byte보다 길어서 하나의 Data Stage에 다 실을 수 없다면, 역시 FX2가 알아서 이를 여러 개의 Data Stage에 실어 보내게 된다.

보낼 데이터가 어디서부터 시작하는지는 우리가 SUDPTRH/L를 써줌으로써 FX2에 알려주게 되지만, 얼마만큼의 데이터를 보낼지 FX2가 어떻게 아는가? 하는 의문이 생기게 된다.
안 생기남? -.-;
그건 SUDPTRCTL 레지스터(Page 15-81)의 설정에 따라 달라지는데,

디폴트 설정인 SDPAUTO = 1 (Auto Mode)일 때에는 FX2가 각 디스크립터의 Length Field를 자동으로 읽어서 알게 된다.

그리고 SDPAUTO = 0 (Manual Mode)로 세팅하게 되면 우리가 직접 EP0BCH/L에 그 길이를 써 주어야 한다.

당근 SDPAUTO = 1일 때에는 SUDPTRH/L 레지스터를 디스크립터를 보내는 용도 외에는 사용할 수 없다. 따라서 SUDPTRH/L 레지스터를 우리가 원하는 (디스크립터가 아닌) 데이터를 호스트로 보내려고 의도한다면, 먼저 SUDPTRCTL 레지스터의 설정을 SDPAUTO = 0 (Manual Mode)로 세팅해 주어야 한다.

FX2의 Default Control Transfer에서 디바이스가 호스트로 데이터를 보내기 위한 방법 중 다를 하나는 EP0BUF[]와 EP0BCH/L 레지스터를 이용하는 방법이다.

먼젓번 강의에서 EP0BUF[]와 EP0BCL은 Data Stage를 통해 호스트로부터 데이터를 받는데 사용했었다.
기억나시남?

그 예와 반대로 이번엔 EP0BUF[] 버퍼에 보내고자 하는 데이터를 쓰고, EP0BCH/L에 그 데이터를 길이를 적어주면 FX가 그 데이터를 Data Stage에 실어 날린다.
이때 EP0BCL을 적는 순간 FX2가 Transfer를 개시하므로, 먼저 EP0BCH를 쓰고, 다음에 EP0BCL을 써야 한다.

case SC_GET_STATUS:에서 위의 방법을 사용하고 있다.

마지막으로 IN Transfer이든 OUT Transfer이든 Data Stage를 통해 데이터를 주고 받고 나면, 마지막 Status Stage를 통해 ACK를 날려서 Transaction을 마무리 하는데, 이것은 SetupCommand()함수의 마지막에 있는 EP0CS |= bmHSNAK;를 통해 이루어 진다.

예를 들어 호스트가 Default Control Endpoint를 통해 디바이스에게 작업지시를 내린다.
그러면 디바이스가 그 명령을 수행하여 그 결과를 다시 호스트에게 보고할 때까지 얼마간의 시간이 걸리는데, 호스트는 그 작업이 언제 끝나는지 알 수 없으므로 일정한 간격으로 디바이스에게 “다 끝났냐” 하고 계속 물어보게 된다.
디바이스는 작업이 다 끝날 때까지는 호스트가 물어볼 때마다 NAK을 날려서 작업이 계속 진행중임을 알리고, 작업이 끝난 후에는 ACK를 날려서 작업완료를 호스트에게 보고하게 된다.

아래 그림이 Control Transfer의 전체적인 그림이다.
마지막 Status Stage의 Empty Data Packet의 방향은 Data Stage의 Data Packet방향의 반대이다.

clip_image001[4]

Setup Stage
        Token Packet : 호스트->디바이스
        Data Packet :   호스트->디바이스 – 명령을 받아라
        Handshake Packet :     디바이스->호스트 – 명령을 잘 받았다
Data Stage
        Token Packet : 호스트->디바이스
        Data Packet :               디바이스->호스트 – 여기 데이터를 보낸다.
        Handshake Packet :                    호스트->디바이스 – 데이터 잘 받았다
Status Stage
        Token Packet : 호스트->디바이스
        Data Packet :   호스트->디바이스 – 명령 수행을 다 끝냈냐?
        Handshake Packet :     디바이스->호스트 – ACK : 명령 수행을 끝냈다.
                                                                         NAK : 쫌 더 지둘려라.

Default Control Transfer에서 Data Stage를 통해 데이터를 호스트로 전송하는 예제는 이미 설명했으므로, 본좌가 따로 안 주겠다.

라고 하면 행자들이 섭섭해 할까 봐, 오늘 볼 예제는 위에서 설명한 Default Control Transfer에서 EP0BUF[]와 EP0BCH/L을 이용해서 데이터를 호스트로 보내는 예제이다.

SETUPDATA의 Value와 Index필드에 16bit의 두 값을 주면 디바이스에서 그 값의 곱을 계산하여 Data Stage를 통해 그 결과(32bit)를 반환하는 예제이다.
UniHigh1.3.zip

예제가 워낙 간단하니 따로 설명은 안 하겠다.
추가한 코드도 몇 줄 안 된다.
함 보시라.

다만 결과로 반환 받아야 할 값이 4 Byte이므로, EZ-USB Control Panel에서 Dir은 1 IN으로 Length는 4로 주어야 한다.

clip_image002

오늘로서 Default Control Transfer를 끝내고 낼은 Interrupt Endpoint를 통해 디바이스에 버튼이 눌렸음을 호스트로 알리는 예제를 함 만들어 보자.

댓글 남기기

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

WordPress.com 로고

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

Twitter 사진

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

Facebook 사진

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

Google+ photo

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

%s에 연결하는 중

%d 블로거가 이것을 좋아합니다: