2014/10/22 11:31

AVR Serial/HID의 간단한 설명.

 HID장치를 간단하게 시리얼 통신처럼 이용할 수 있는 방법은 CDC ACM 방법이 운영체제가 막아서 생기는 문제는 해결할 수 있다. 이 방법이 꼭 장점이 강한 것은 아니지만, 간단한 테스트를 위한 하드웨어에서의 응용은 나쁘지 않을거라고 생각된다.


 기본적으로 HID의 사용되는 프로그래밍 방법은 같고 단지 주의할 점만 존재한다. 호스트 컴퓨터에서 장치로 USB통해 정보는 받는 부분에 control전송과 인터럽트 전송을 모두 거치는 usbFunctionWriteOut을 쓰는데, 이것은 별로 문제가 되지 않는다. 단지 가끔 NULL데이터를 보내므로 펌웨어에서 체크를 하면 된다. 그리고 데이터의 길이가 버퍼의 길이와 맞추는 작업도 필요하다. 이것은 각각의 구현에 따른 변경이 다르므로 다른 게시물에 업로드한 소스를 확인하면 대충 이해하기 쉽다.


 가장 크게 주의할 점은 바로 HID 레포트 정보의 선언으로 장치에서 호스트 컴퓨터로 보내는 크기는 8바이트가 되어야 한다. 그렇지 않으면 데이터가 전혀 전송이 되지 않는다. 호스트 컴퓨터에서 장치로 전송되는 크기는 크게 문제가 없지만 64이하로 만들어주는 것이 좋다.


PROGMEM const char usbHidReportDescriptor[] = {
  0x06, 0xa0, 0xff, // USAGE_PAGE (Vendor Defined Page 1)
  0x09, 0x01,       // USAGE (Vendor Usage 1)
  0xa1, 0x01,       // COLLECTION (Application)

  // Input Report
  0x09, 0x02,       // Usage ID - vendor defined
  0x15, 0x00,       // Logical Minimum (0)
  0x26, 0xFF, 0x00, // Logical Maximum (255)
  0x75, 0x08,       // Report Size (8 bits)
  0x95, 0x08,       // Report Count (8 fields), must be 8
  0x81, 0x02,       // Input (Data, Variable, Absolute)

  // Output report
  0x09, 0x03,       // Usage ID - vendor defined
  0x15, 0x00,       // Logical Minimum (0)
  0x26, 0xFF, 0x00, // Logical Maximum (255)
  0x75, 0x08,       // Report Size (8 bits)
  0x95, 0x16,       // Report Count (16 fields)
  0x91, 0x02,       // Output (Data, Variable, Absolute)

  0xc0              // END_COLLECTION
};


 기본적인 레포트의 선언은 위와 같은데, 항상 명칭은 호스트 컴퓨터를 중심으로 표현된다. Input는 장치에서 컴퓨터로 보내는 것으로 Report Size와 Report Count는 반드시 8바이트가 되어야 한다. 하드웨어 지원이 된다면 이런 제한이 없다고 하는데 하드웨어 USB 지원이 안되는 AVR은 저속 장치로 인식되는 탓에 어쩔 수 없다.


 Output 레포트의 크기는 변화를 줘도 아무런 문제가 없다.


 레포트 선언은 이렇게 간단하고, v-usb의 선언에서 데이터 전송을 위한 부분을 처리하도록 작성하는데 몇개의 함수만 만들어주면 간단히 끝난다.


usbMsgLen_t usbFunctionSetup(uchar data[8])
{
    return 0;
}

uchar usbFunctionRead(uchar *data, uchar len)
{
    return 0;
}

void usbFunctionWriteOut(uchar *data, uchar len)
{
uchar i,c;
    if(len>0) {
        if( (*data==0x0d) || (*data==0x0a) )
            return;
        if(len>HIDSERIAL_INBUFFER_SIZE) len=HIDSERIAL_INBUFFER_SIZE;
        i=0;
        while(i<len) {
            c=data[i];
            inBuffer[i]=c;
            i++;
            if(c==0) break;
        }
        received=1;
        recv_len=i;
    }
}


 usbFunctionSetup은 컴퓨터에 장치의 정보들을 설정하고 주고 받거나 컨트롤 전송을 위해 쓰이는데, 이 구현에서는 따로 크게 코딩할 부분이 없다.


 usbFunctionRead는 장치로 데이터를 보내는 방법을 위한 것으로 마찬가지로 컨트롤 전송을 위한 것으로 인터럽트 전송을 하는 이 방법에서는 쓸모가 없다.


 usbFunctionWriteOut은 호스트 컴퓨터에서 장치로 보내는 데이터를 처리할 때 쓰이는데, 이곳에서 장치의 버퍼에 데이터를 저장하면 된다. 설명에는 컨트롤 전송도 이 함수를 통해 데이터를 받을 수 있다고 되어 있다. 데이터가 다 전송되었다는 것을 확인할 방법을 구현하는게 좋다.


int main(void)
{
    odDebugInit();
    hardwareInit();
    usbInit();

    sei();
    for(;;){    /* main event loop */
        wdt_reset();
        usbPoll();

        if( usbInterruptIsReady() && (received != 0) )
          Translate_buffer(inBuffer);

...

    if(iwptr>0) {
        rx_buf[iwptr]=0;
        usbSetInterrupt(rx_buf,8);
        if(iwptr>8) {
            while(!usbInterruptIsReady()) {
                wdt_reset();
                usbPoll();
            }
            usbSetInterrupt(rx_buf+8,8);
        }
        iwptr=0;
    }

    }
...

    return 0;
}


 이렇게 간단히 선언하고 위와 같이 usbPoll()과 usbInterruptIsReady() 함수로 계속 상태를 확인하고 데이터의 전송에는 usbSetInterrupt(data, 8)과 같이 사용하면 된다. 8로 고정된 이유는 이미 설명했다. 만약 데이터가 길다면 usbPoll()과 usbInterruptIsReady()로 상태를 체크한 후에 usbSetInterrupt(...,8)로 다시 보내주면 된다. 8바이트씩 보내는 것이라 계속 보내준다면 크게 길이의 제한은 없다고 생각된다.


그리고 usbconfig.h의 내용들은 대충 이렇다.

...

#define USB_CFG_HAVE_INTRIN_ENDPOINT    1

#define USB_CFG_HAVE_INTROUT_ENDPOINT   1 

#define USB_CFG_IMPLEMENT_FN_WRITEOUT   1

...

#define USB_CFG_INTERFACE_CLASS     3       /* HID class */
#define USB_CFG_INTERFACE_SUBCLASS  0     
#define USB_CFG_INTERFACE_PROTOCOL  0    

...

#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH    34

...



 특별한 것은 없는 방법론이기 때문에 그냥 따라하면 끝이다. 탐구를 하고 싶다면 삽질을 해봐도 좋을 일이다. =_=;



cdcio.2009-07-15-serhid-4313.zip



저작자 표시 비영리 변경 금지

'하드웨어' 카테고리의 다른 글

AVR Serial/HID의 간단한 설명.  (0) 2014/10/22
AVR Serial HID 구현.  (0) 2014/10/21
USB CDC는 막힌 듯?  (0) 2014/10/20
USBTiny 실험.  (0) 2014/10/17
avr-gcc 4.9.2  (0) 2014/10/14
USBTinyISP 만들기.  (0) 2014/10/09
Trackback 0 Comment 0
2014/10/21 23:28

AVR Serial HID 구현.

AVR의 소프트웨어 CDC는 운영체제에서 저속이기 때문에 장치의 연결을 끊는 것으로 확인. 그래서 cdc-io를 포기하려 했으나 YAT란 터미널 프로그램에 Serial HID라는 기능이 존재. 구현을 아무리 찾아봐도 없고 결국 삽질을 해가며 직접 구현.


 입으로 설명하기엔 너무 많이 모르기 때문에 곤란하고 완성된 소스를 첨부. 이 소스에는 V-USB에서 인터럽트 OUT이 가능한 수정이 담겨있다. 이 수정이 약간 틀려서 교정을 봤다.

 예제 4번만 수정되어 있고 출처는 http://lackawanna.hackhut.com/2011/10/06/using-v-usb-and-the-hid-class-part-iiiiii/


avr-all_examples-serhid.zip


 USB HID의 레포트를 만드는게 어렵다면 그냥 복사해서 사용하면 된다. 설정시 압축파일에 들어있는 usbconfig의 내용도 중요하다. YAT로 입력받은 문자를 16진수로 변환해서 다시 보여주는 예제. YAT를 실행에는 관리자 권한이 필요하다. 그냥 띄우면 HID가 장치가 목록에 안보인다.


 중요한 것은 cdc-io를 이 기능에 맞게 다시 변환하는 것. 그리고 2313A의 용량 증설판인 ATtiny4313을 사용해서 기능을 확장. 4096워드를 사용하니 정말 편하다. 백번 정도 굽고 지우고를 반복했는데 고장이 안났다. 그리고 한번은 전원을 거꾸로 연결했는데 열이 펄펄 =_=; 다시 제대로 연결하니 생생했다. PIC는 바로 고장나던데;


 그렇게 CDC-IO의 2313용의 펌웨어 소스에 많은 수정을 가해서 비트 단위나 몇몇 기능의 확장을 꾀했다.

 둘다 GPL이라 =ㅅ=;



cdcio.2009-07-15-serhid-portfix.zip

 (4313의 구현에서 포트 이름의 레지스터 부분이 잘못되어서 수정.)

 결과물은 이렇다.



 명령의 입력은 "<16진 데이터> <공백> <레지스터명 혹은 16진수> <공백> <명령>" 이런 식이다.

 ?는 값을 알아보고(비트 가능), =는 값을 대입하고(비트 가능), &는 AND연산, ^는 XOR 연산, |는 OR연산. 논리 연산은 비트를 구현하지 않았다. @만 입력하면 "cdc-io"문자열이 표시된다.


 또하나의 삽질 끝. 노하우 하나 획득.



저작자 표시 비영리 변경 금지

'하드웨어' 카테고리의 다른 글

AVR Serial/HID의 간단한 설명.  (0) 2014/10/22
AVR Serial HID 구현.  (0) 2014/10/21
USB CDC는 막힌 듯?  (0) 2014/10/20
USBTiny 실험.  (0) 2014/10/17
avr-gcc 4.9.2  (0) 2014/10/14
USBTinyISP 만들기.  (0) 2014/10/09
Trackback 0 Comment 0
2014/10/20 08:37

USB CDC는 막힌 듯?

 USB 구현에 CDC라는게 있는데 통신장치 구현에 사용되는 표준으로 USB의 장치에 기입되는 정보는 바탕으로 ACM으로 모뎀처럼 사용할 수 있는게 있었는데, 최신의 운영체제에서는 막힌 것 같다. 윈도우즈의 경우에는 usbser.sys라는 표준 드라이버가 있는데 인식을 못하는 현상이 발생. 망했다.


 이 문제는 해결하는 가장 좋은 방법은 HID로 설정을 변경하는 것. 마우스나 키보드, 조이스틱이 구현이 가능하다. USBTinyISP 조차도 드라이버는 libusb를 통해서 사용을 하고 있다. USB-Serial의 경우도 대부분 CDC-ACM은 피하고 있는 것을 보니 안되나보다.


 좀 더 확인을 해보고 설정을 바꿔야 할 듯.


저작자 표시 비영리 변경 금지

'하드웨어' 카테고리의 다른 글

AVR Serial/HID의 간단한 설명.  (0) 2014/10/22
AVR Serial HID 구현.  (0) 2014/10/21
USB CDC는 막힌 듯?  (0) 2014/10/20
USBTiny 실험.  (0) 2014/10/17
avr-gcc 4.9.2  (0) 2014/10/14
USBTinyISP 만들기.  (0) 2014/10/09
Trackback 0 Comment 0


티스토리 툴바