두둥~ 드디어 bulkloop.c 그 첫번째
본좌. 한 이틀간 회로와 납땜 얘기로 변죽만 울렸다.
오늘은 바로 핵심으로 돌진한다.

이제까지 desc.a51 파일과 fw.c 파일을 디볐는데,
실질적으로 bulkloop 프로젝트의 핵심은 bullkloop.c 파일에 있다.

이전에 이미 언급했던 것처럼
그 중에서도 핵심은 TD_Init(), DR_VendorCmnd(), TD_Poll()
이 세 함수가 되겠다.

주말에 술 마시느라 기억력을 고스란히 술잔에 반납하신 행자들을 위해
본좌가 졸라리 싫어하는 리바이벌을 함 하자면,

TD_Init()은
우리가 필요한 초기화 루틴을 넣으라고 FrameWork님께서 마련해 놓으신 자리이고,

DR_VendorCmnd()은
Default Control Endpoint( Endpoint 0 )를 통해 호스트로부터 오는 명령 중에서
FrameWork님께서 처리하지 않는
우리만의 명령을 처리하기 위한 루틴을 위한 함수이고,

TD_Poll()은
Poll이란 단어의 뉘앙스에서 팍 느껴지듯이 (안 느껴지남?)
루프를 돌면서 계속 할 일이 있는지 체크하다가
할 일이 생기면 처리하는 그런 코드를 담은 함수가 되겠다.
여기가 바로 bulkloop의 핵심이다.


잠시 딴길로 빠지자면,
이 bulkloop의 예에서처럼
polling으로 일을 처리하는 코드는
처음에 짜기는 편하지만
프로세서가 처리해야 할 일이 많아지기 시작하면
이런 “마이크로”프로세서에서는 쥐약이다.
우리가 쓰는 컴퓨터처럼 운영체제가 멀티프로세싱을 지원하는 것도 아니어서
한가지 작업을 하는데 시간을 많이 잡아먹어 버리면
그 뒤에 처리를 기다리는 Time Critical한 작업들도 전부 다 지연되어버린다.
따라서 인터럽트 우선순위를 잘 이용한 Interrupt driven 방식으로
코드를 짜기를 권한다.
Bulkloop는 예제이니 그냥 그런가 보다 하고 넘어가자.


TD_Init()과 DR_VendorCmnd()는 후에 밟아보기로 하고,
오늘은 바로 본론(TD_Poll() )으로 들어간다.

Bulkloop가 호스트가 보내는 데이터를 FIFO에 저장했다가
호스트가 데이터를 요구하면
FIFO의 데이터를 차례로 꺼내주는 예제이니만큼
여기에 이런 기능이 구현되어 있을 것이다.

if(!(EP2468STAT & bmEP2EMPTY))
{
어쩌구
}
if(!(EP2468STAT & bmEP4EMPTY))
{
저쩌구
}


첫 번째 if 문은 Endpoint 2로 들어오는 데이터를 Endpoint 6로 내보내는 코드이고,
두 번째 if 문은 Endpoint 4로 들어오는 데이터를 Endpoint 8로 내보내는 코드이다.

두 코드는 데이터를 IN/OUT하는 엔드포인트만 다를 뿐,
하는 일은 똑 같으므로
첫 번째 if문만 설명하도록 하겠다.

먼저
if( !( EP2468STAT & bmEP2EMPTY ) )
자 통빡을 굴려보자. 데굴데굴
EP2468STAT은 무슨 레지스터 같고,
bmEP2EMPTY는 읽어보니 EP2(엔드포인트 투)가 비었다는 걸 나타내는 것 같다.
통빡들 다 굴리셨남?
다 굴렸으면 데이터쉬트 찾아볼 차례다.
다들 T.R.M(Technical Reference Manual)을 뒤비시라.

본좌는 예전에 뒤볐었기 때문에 그냥 혼자 진도 나간다.
만일 EP2의 버퍼가 비어있다면
( EP2468STAT & bmEP2EMPTY ) == TRUE 일 것이고
따라서
( !( EP2468STAT & bmEP2EMPTY ) ) == FALSE일 것이다.
고로 if문을 수행하지 않는다.

정리하면
EP2의 버퍼가 비어있다면 if문을 수행하지 않는다는 말이다.
바꿔 말하면
EP2의 버퍼가 비어있지 않다면 if문으로 들어가 뭔 짓거리를 한다는 말쌈이다.

EP2의 버퍼가 비어있지 않을 때
어떤 짓거리를 하는지 따라 들어가 보자.

if(!(EP2468STAT & bmEP6FULL))
어라~! 비슷한게 또 나왔네?
이번엔 막바로 설명하면
EP6의 버퍼가 꽉차있지 않다면 if문으로 들어가 뭔 짓거리를 한다는 말쌈이다.

두 if 문을 합쳐서 생각해보면
(데이터를 받는) EP2의 FIFO에 뭔가가 들어왔고,
(데이터를 보내는) EP6의 FIFO가 꽉 차서 더 이상 (호스트로 ) 데이터를 보낼 수 없지 않다면
이 짓거리를 한다.
{
APTR1H = MSB( &EP2FIFOBUF );
APTR1L = LSB( &EP2FIFOBUF );

AUTOPTRH2 = MSB( &EP6FIFOBUF );
AUTOPTRL2 = LSB( &EP6FIFOBUF );

count = (EP2BCH << 8) + EP2BCL;

for( i = 0x0000; i < count; i++ )
{
EXTAUTODAT2 = EXTAUTODAT1;
}
EP6BCH = EP2BCH;
SYNCDELAY;
EP6BCL = EP2BCL;
SYNCDELAY;
EP2BCL = 0x80;
}

라는 말쌈이 되겠다.

APTR1H, APTR1L과
AUTOPTRH2, AUTOPTRL2는
각각 Auto Pointer1과 Auto Pointer2를 위한 레지스터가 되겠다.

이 오토포인터가 뭐시기냐 하면

보통 버퍼에서 데이터를 한 바이트(워드)식 불러다가 처리 하고자 할때에는
다음과 같은 절차를 반복하게 된다.
1. 포인터를 버퍼의 맨 앞을 가리키도록 초기화한다.
2. 포인터가 가리키는 버퍼의 주소에 있는 데이터를 가져다가 지지고 볶는다.
3. 포인터를 하나 증가시킨다.
4. 원하는 만큼 2,3번을 반복한다.

그런데
Auto pointer를 쓰게 되면 3번의 절차를 생략해도
버퍼에서 데이터를 가져올 때마다 포인터가 자동으로 증가한다.

그래서 우리는
1. 포인터를 버퍼의 맨 앞을 가리키도록 초기화한다.
2. 포인터가 가리키는 버퍼의 주소에 있는 데이터를 가져다가 지지고 볶는다.
3. 원하는 만큼 2번을 반복한다.
요렇게만 해도 된다는 거다.
쫌 편해 보이지 않는가?
아님 말고.


물론 버퍼에서 데이터를 가져올 때마다 포인터를 감소시킬 수도 있고,
물론 버퍼에서 데이터를 가져올 때마다 포인터를 증가시킬 수도 있고,
물론 버퍼에 데이터를 쓸 때마다 포인터를 감소시킬 수도 있고,
물론 버퍼에 데이터를 쓸 때마다 포인터를 증가시킬 수도 있다.
그건 Auto pointer를 어떻게 세팅하는가에 따라, 그때그때~ 달라여~.







Auto pointer에 대해 자세한 것은 나중에 살피기로 하고,
다시 진도 나가자.
APTR1H = MSB( &EP2FIFOBUF );
APTR1L = LSB( &EP2FIFOBUF );

AUTOPTRH2 = MSB( &EP6FIFOBUF );
AUTOPTRL2 = LSB( &EP6FIFOBUF );

오토포인터1은 EP2 FIFO 버퍼의 시작주소를 가리키도록,
오토포인터2은 EP6 FIFO 버퍼의 시작주소를 가리키도록,
초기화 하고 있다.

count = (EP2BCH << 8) + EP2BCL;
count라는 WORD형( 2 byte ) 변수의 상위바이트에는 EP2BCH를
하위 바이트에는 EP2BCL가 들어가도록 우겨넣고 있다.

EP2BCH/EP2BCL가 뭔지
머리 떼고, 꼬리 떼고 다짜고짜 설명하면
호스트로부터 EP2 버퍼에 데이터가 얼마만큼 들어온 지를 나타내는 레지스터가 되겠다.
(EP2 Byte Count High/Low)

호스트가 데이터를 우리 디바이스에게 날리면
FX2는 그 데이터를 받아서 FIFO에 차곡차곡 넣은 다음
들어온 데이터가 얼마만큼인지를 EP2BCH/EP2BCL에 써 넣는다.
그리고 나서 요 앞서 보았던 EP2468STAT 레지스터에
딸랑~딸랑~
EP2에 데이터 들어왔어요 하고
해당 비트(bmEP2EMPTY)를 세팅하는 것이다.

FX2 졸라 착하지 않은가?
우리는 USB 트렌젝션(transaction)이 어떻게 이루어지는지
아직 알지도 못하는데,
FX2가 다 알아서 해버린다.

그 다음
for( i = 0x0000; i < count; i++ )
{
EXTAUTODAT2 = EXTAUTODAT1;
}

들어온 데이터 바이트 수 만큼 뺑뺑이를 돌리는데,
어랍쇼?
EXTAUTODAT2는 뭐고, EXTAUTODAT1는 또 뭐야?

바로 앞서 설명한 Auto pointer가 가리키는 버퍼의 데이터가 되시겠다.
C에서의 참조연산자 “*”라고 생각하시면 딱이다.
*Autopointer2 == EXTAUTODAT2

Autopointer2는 EP6 FIFO Buffer의 시작번지로 초기화하고,
Autopointer1는 EP2 FIFO Buffer의 시작번지로 초기화 한 거 기억 하시남?
기억 안 나면 언능 앞에 가서 보고 오셔~.
루프를 한번 돌 때마다
Autopointer2, Autopointer1은
각 버퍼의 처음 주소부터 시작해서 자동으로 1씩 증가 할 것이고,
EXTAUTODAT”x”는 Autopointer”x”가 가리키는 번지의 데이터이므로
For 루프안에서 하는 일은
결국
EP2 버퍼의 데이터를 EP6로 고스란히 옮기는 거이 되겠다.

그리고 나서
EP6BCH = EP2BCH;
SYNCDELAY;
EP6BCL = EP2BCL;
SYNCDELAY;

SYNCDELAY;는 일단 생까자.
뭔 일을 하는 명령어는 아니다.

그럼 이렇게 된다.
EP6BCH = EP2BCH;
EP6BCL = EP2BCL;

보라 EP2의 EPxBCH/L를 EP6의 그것에 고스란히 복사하고 있다.
얼랄라리오.
아까는 EPxBCH/L가 받은 데이터의 바이트수가 들어있는 레지스터 라메?
하시는 행자분께 박수를.
암 생각없는 행자는 1분간 olo잡고 반성.

EP”x”BCH/L에서 “x”가 OUT Endpoint를 나타낸다면,
본좌가 앞서 설명한게 맞고,
EP”x”BCH/L에서 “x”가 IN Endpoint를 나타낸다면,
호스트에게 보낼 바이트 수를 저장하는 레지스터가 된다.
그때 그때 다른 쓰임세 되겠다.
왜 그러냐고 묻지 마라.
Cypress에서 그렇게 만들었을 뿐이다.
(아울러 IN transfer가 디바이스->호스트로 데이터가 전송된다는 것도 한번 더 상기시켜 드린다. - host 입장에서 바라보기)

그러니까 정리해보면
EP2로 받은 데이터를
고대로
EP6의 버퍼에 카피하고,
EP6BCH/L을 기입함으로써
“나 이만큼 데이터를 날릴 꺼야” 라고
장전까지 마친 상태가 여기까지이다.

-to be continue-

한 줄 남았는데 마침.
왠지 낼이 기대 되지 않는가? -.-;;
by 바람처럼날다 | 2005/04/11 22:16 | FX2 펌웨어 강좌 | 트랙백 | 핑백(2) | 덧글(3)
트랙백 주소 : http://muosys.egloos.com/tb/75316
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Linked at 두둥~ 드디어 bulkloop.. at 2008/03/26 09:40

... http://muosys.egloos.com/75316</a> 본좌. 한 이틀간 회로와 납땜 얘기로 변죽만 울렸다.오늘은 바로 핵심으로 돌진한다. 이제까지 desc.a51 파일과 fw.c 파일을 디볐는데, 실질적으로 bulkloop 프로젝트의 핵심은 bullkloop.c 파일에 있다. 이전에 이미 언급했던 것처럼 그 중에서도 핵심은 TD_Init(), DR_VendorCmnd(), TD_Poll() 이 세 함수가 되겠다. 주말에 술 마시느라 ... more

Linked at Bulk Endpoint로 데.. at 2008/03/31 23:32

... http://muosys.egloos.com/75316</a>를 다시 함 보시든지, 병원 가서 치매 치료를 받아보시라. 소스 설명은 끝이고…아래의 회로를 꾸미시라.Host에서 날라오는 데이터 대로 LED가 점등되도록 함 해보자. 어떻게 테스트를 하냐 하면 펌웨어를 다운로드 한 후에, Get Pipe 하고, Pipe 1을 선택한 후에, File Transfer버튼을 눌러 본좌가 제공한 파일을 지정해 주면 LED가 파일의 데이터 대로 깜빡거린다.data. ... more

Commented by 유대상 at 2005/04/12 10:54
정말 많이 배우고 있습니다.
님 파이팅입니다.
자주 자주 들르께요..
다음 강좌 기대하겠습니다.
Commented by 침착이 at 2005/04/12 12:07
감사드립니다.
아침에 와서 재일 먼저 하는 일이 바람teacher님의 강의를 보는 일이 되어버렸습니다.
Commented by 까불이 at 2008/10/11 10:30
olo 강의 볼때마다 잡는...

:         :

:

비공개 덧글

< 이전페이지 다음페이지 >