로그인 | 회원가입
   이용안내    장바구니    주문조회    마이쇼핑    게시판
상품검색 검색 
아이디  
비밀번호
보안접속 보안접속
회원가입
  아이디찾기
  비밀번호찾기
상품목록
  ARM
  PIC
  AVR
  DSP
  MAXQ
  MSP430
  OTHER
게시판
공지사항
자유게시판
강좌-USB기타
자료실
샘플 기획전
전화: 031-429-0845
팩스: 031-477-1407
운영시간
  09:00 ~ 18:00
 
현재위치: > 게시판 > 강좌-USB기타
강좌-USB기타
USB및 기타자료입니다.


찾기
제목 UniFull 펌웨어 v1.1 - Default Control Endpoint 를 이용한 LED On/Off 0  추천하기
작성자 글쓴이 작성일 2014-10-29 16:22:33 조회수 441
   
   

USB 디바이스와 통신할 어플리케이션이 준비 되었으면

이제 USB 디바이스의 펌웨어를 작성할 차례이다.

 

먼저 위의 펌웨어 소스코드를 받아서 AVR Studio로 열어보시라.

 

그리고 먼저 unifulldev.h를 열어보시라.

다음과 같은 코드들이 들어있다.

#ifndef __UNIFULLDEV_H__

#define __UNIFULLDEV_H__

 

#define LED_ON      0x00

#define LED_OFF 0x01

 

#endif

 

어플리케이션 프로그래머와 드라이버 프로그래머가 상의한 결과물이 UniFullUsr.h 이듯이,

드라이버 프로그래머와 펌웨어 프로그래머가 상의한 결과물은 unifulldev.h 이다.

 

LED를 키는 경우를 예로 들어 설명하면,

어플리케이션에서 IOCTL_UNIFULL_LED_ON이라는 명령을 드라이버로 내려 보내면,

드라이버에서는 이에 상응하는 LED_ON을 펌웨어로 내려 보내는 것이다.

 

그럼 단지 장치관리자에 잡히기만 하는 기능(?) 만 있던 UniFull Firmware v1.0과

LED를 키고 끄는 명령을 알아들어 실행하는 UniFull Firmware v1.1의 차이점이 무언지 알아보자.

 

unifull.c의 control_handler()에

다음의 코드가 추가 되었고,

else if( type == USB_VENDOR_REQUEST )

    {

        switch(req)

        {

        case LED_ON:

            led_on();

            break;

        case LED_OFF:

            led_off();

            break;

        default:

            reserved();

            break;

        }

    }

 

또, 그 아래에 실제로 LED를 키고, 끄는 다음의 함수 두 개가 추가 되었다.

void led_on(void)

{

    asm("cbi 0x18, 0");

    single_transmit(0, 0);

}

 

void led_off(void)

{

    asm("sbi 0x18, 0");

    single_transmit(0, 0);

}

물론 이 함수들의 함수원형( function prototype )도 unifull.h에 추가해 주었다.

 

이게 다다.

 

 

 

control_handler()는 Setup Packet이 도착 했을 때 호출되는 함수다.

즉, Default Control Endpoint를 통해 뭔가가 도착했을 때는 여길로 겨 들어 온다는 말쌈이닷.

 

control_handler()에 새로 추가된

else if( type == USB_VENDOR_REQUEST )…

를 살펴보기 전에,

 

먼저 unifull.h를 보면

#define USB_REQUEST_TYPE_MASK    (unsigned char)0x60

와 함께 구조체

typedef struct _DEVICE_REQUEST

{

    unsigned char bmRequestType;

    unsigned char bRequest;

    unsigned short wValue;

    unsigned short wIndex;

    unsigned short wLength;

} DEVICE_REQUEST;

가 선언되어 있다.

 

이전 강의에서

Setup Packet은 크게 SETUP Stage, DATA Stage, STATUS Stage의 세개의 Stage로 이루어지고,

SETUP Stage에는 우리에게 “의미가 있는 8 byte 데이터”가 있다 라고 야부리를 풀었었는데, 기억하시남? 참 기억력도 좋으3.

 

Default Control Endpoint를 통해 디바이스에 Setup Packet이 도착하면

그 8 byte 짜리 데이터가 DEVICE_REQUEST라는 구조체에 담겨서 control_handler()로 넘겨진다.

( 어디서? isr.c의 ep0_rxdone() 함수에서. 뭐 굳이 알 필요는 없다. )

 

control_handler()의 앞부분에

type = DeviceRequest.bmRequestType & USB_REQUEST_TYPE_MASK;

라고 있다. 찾으셨남?

이 말인 즉슨.

DEVICE_REQUEST 구조체에 들어있는 8 바이트의 데이터들 중에서

첫 번째 바이트( bmRequestType ) 중에서도

5,6번째 bit ( USB_REQUEST_TYPE_MASK == 0x60 == 0110 0000 )만을 추출해서 type이라는 변수에 집어 넣어라

라는 말이 되것다.

 

다시 unifull.h에 보면

#define USB_STANDARD_REQUEST    (unsigned char)0x00

#define USB_CLASS_REQUEST       (unsigned char)0x20

#define USB_VENDOR_REQUEST  (unsigned char)0x40

라고 선언되어 있는데,

이 세가지가 type이라는 변수와 대응될 수 있는 모든 경우의 가짓수이다.

USB_STANDARD_REQUEST는 chap_9.c에 선언되어 있는 함수들

즉, 디바이스 디스크립터를 보내라, configuration 디스크립터를 보내라 등등이 USB_STANDARD_REQUEST가 되겠고,

USB.org에서 정의한 Class에 포함되는 장치에 내려 보내는 명령이 USB_CLASS_REQUEST가 되겠다.

( 우리의 경우엔 해당사항 없음이다. )

마지막으로 USB_VENDOR_REQUEST는 우리가 우리의 목적에 맞게 Default Control Endpoint( Endpoint 0 )를 통해 내려 보낼 수 있는 명령이다.

 

여기까지를 종합하면

이제 else if( type == USB_VENDOR_REQUEST ) 이 부분이 이해가 가시리라 믿는다.

 

 

우선 unifull.h의

#define USB_REQUEST_MASK        (unsigned char)0x0F

를 참조한 후에, control_handler()의 다음 코드를 보면

req = DeviceRequest.bRequest & USB_REQUEST_MASK;

switch(req)

DEVICE_REQUEST의 두번째 바이트( bRequest )의 하위 니블(USB_REQUEST_MASK==0x0F )을 가지고

구체적으로 Vender Request가 뭐냐를 해석하고 있음을 알 수 있다.

 

머리가 빠개지실 것 같은가?

이제까지 설명한 것들에 대해 세줄 요약을 한다.

1.  펌웨어 프로그래머와 드라이버 프로그래머가 머리를 맞대고 unifulldev.h를 내 놓았다.

2.  드라이버(호스트)는 Endpoint 0를 통해 LED ON/OFF 명령을 날린다.

3.  펌웨어 프로그래머는 control_handler()의     …else if( type == USB_VENDOR_REQUEST )…안에서 이를 받아 처리하면 된다.

이상~입니다.

 

 

void led_on(void)

{

    asm("cbi 0x18, 0");

    single_transmit(0, 0);

}

 

void led_off(void)

{

    asm("sbi 0x18, 0");

    single_transmit(0, 0);

}

에 대해 잠깐 언급하고 넘어가야겠다.

 

cbi/sbi는 ATmega128 Datasheet에 보면 다음과 같이 나와 있다.

SBI X, Y : Set Bit Y in I/O Register X

CBI X, Y : Clear Bit Y in I/O Register X

 

그리고 0x18는 PORTB 레지스터를 뜻한다.

즉, PORTB 레지스터의 0번째 비트를 Set/Reset하기 위한 코드이다.

 

왜 굳이 asm 코드를 썼는고 하니,

원래는 이 부분을

PORTB |= _BV( PB0 );    // Set

PORTB &= ~_BV( PB0 );   // Reset

요렇게 C코드로 작성했었는데,

전능하신 gcc 컴파일러 께서 문맥상 이 코드는 암데도 쓸모가 없군 하시고는

"warning : statement with no effect"라는 메시지를 출력하시면서

컴파일된 결과물(hex 파일)에서는 싹 빼버리셨던 것이다. 할렐루야~.

본좌 그런 줄도 모르고 되야 하는데 왜 안될까를 고민하면서 날밤을 깟더랬다. 미~쑤미?

어느날 디버깅 중에 Disassembler Window를 열어 led_on/off 함수를 들여다 보니

당연히 들어 있어야 할 Set/Reset을 위한 코드가 없더라. 허탈~.

아마 gcc의 optimization level을 낮추면 해결될 문제일 것이리라.

하지만 본좌는 위의 방법을 택했다. 본좌 맘이다.

 

본좌 저런 삽질을 하고 나서

앞서 행자들에게 Disassembler Window를 잘 들여다 보라고 충고를 했던 것이다.

 

 

마지막으로 우리가 만든 펌웨어가 잘 작동할 지 테스트할 회로를 꾸며서 테스트 해 보자.

 

회로는 다음과 같다.

 

 

 

UniFull보드에 JTAG을 연결하고, USB 포트를 끼운다.

펌웨어 코드를 빌드한 후( F7 ),

Start Debugging 버튼을 누르면( Ctl+Shift+Alt+F5 ) 펌웨어가 UniHigh보드로 쭉쭉 다운로드 된다.

이제 디버깅 모드를 빠져 나와( Ctl+Shift+F5 ) 다운로딩된 펌웨어에 따라 보드가 동작하도록 하시라.

이제 바로 이전 강의에서 만든 어플리케이션으로 LED를 제어 할 수 있다.

댓글달기 회원에게만 댓글 작성 권한이 있습니다. 회원가입하여 정보공유를 하면 좋겠습니다.
첨부파일
답변
  스팸신고 스팸해제
글쓰기
 
이전글 USB 디바이스와 통신하기 위한 어플리케이션 작성 2/2
다음글 [부록] STALL & USB BUS RESET
 
 
| 회사소개 | 이용약관 | 개인정보취급방침 | 이용안내
Copyright ⓒ 2010 KitKorea All rights reserved.
전화 : 031-429-0845 FAX : 031-477-1407
Contact open@kitkorea.com for more information.
법인명(상호):인터전자 주식회사 주소:14120 경기도 안양시 동안구 흥안대로 112-1 (호계동)
사업자 등록번호 안내 [138-81-28277] / 통신판매업 신고 제 안양 1753호 [사업자정보확인]
개인정보보호책임자 :홍성호(open@kitkorea.com) / 대표자(성명):홍성호
cafe24