LPC1343 USB HID example

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

LPC1343 USB HID example

1,225 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by deBoogle on Tue May 21 04:33:29 MST 2013
Hi folks,
Just did a search for USB and got an error back from the engine, so in lieu of being able to search for my topic first....

I am new to USB and could do with a few pointers on something.  I have programmed the LPC1343 with the USB HID example and can read and connect to it fine using some C# code I have got from Jan Axelson's page (which is a great resource).

But i need a rough idea of which areas I need to look at modifying in order to  create an InReport of about 255 bytes in the LPC example code.

1). HID report descripto will need to modified, exspecially report count and size and probably logical max as it will be numerical vals up to maximum binary val.  But, which bits need changing as there are a few report count/size parts to the descriptor:

const uint8_t HID_ReportDescriptor[] = {
  HID_UsagePageVendor(0x00),
  HID_Usage(0x01),
  HID_Collection(HID_Application),
    HID_UsagePage(HID_USAGE_PAGE_BUTTON),
    HID_UsageMin(1),
    HID_UsageMax(3),
    [COLOR=Blue]HID_LogicalMin(0),
    HID_LogicalMax(1),
    HID_ReportCount(3),
    HID_ReportSize(1),[/COLOR]
    HID_Input(HID_Data | HID_Variable | HID_Absolute),
    HID_ReportCount(1),
    HID_ReportSize(5),
    HID_Input(HID_Constant),
    HID_UsagePage(HID_USAGE_PAGE_LED),
    HID_Usage(HID_USAGE_LED_GENERIC_INDICATOR),
[COLOR=Lime]    HID_LogicalMin(0),
    HID_LogicalMax(1),
    HID_ReportCount(8),
    HID_ReportSize(1),[/COLOR]
    HID_Output(HID_Data | HID_Variable | HID_Absolute),
  HID_EndCollection,
};

The bit marked in green seems to be the OutReport which the LPC receives, if I modify the first reference to report counts sizes (in Blue) I fail to enumerate.

2).  Which other functions will require modification?, I have seen the GetInReport fumction, which is called by the USB_EndPoint1 when it receives a request for InReport and also the USB_WriteEP function.  Are there any other parts I should be looking at...

if anybody has written some code that already does something similar that I could take a peek at, I would be very grateful. Many thanks in advance
D
0 Kudos
1 Reply

702 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Tsuneo on Tue May 21 11:11:10 MST 2013
To ask on code modification, you have to specify the target code, exactly.
Are you working on usbhid example on examples.lpc13xx.new.zip, in \nxp\LPCXpresso_5.2.4_2122\lpcxpresso\Examples\NXP\LPC1000\LPC13xx folder?


Quote:
But i need a rough idea of which areas I need to look at modifying in order to create an InReport of about 255 bytes in the LPC example code.



You may simplify the report descriptor, as follows,
usbdesc.c

#define HID_INPUT_REPORT_BYTES       255     // up to 255 bytes
#define HID_OUTPUT_REPORT_BYTES      255     // up to 255 bytes
#define HID_FEATURE_REPORT_BYTES     255     // up to 255 bytes

const BYTE HID_ReportDescriptor[] = {
  HID_UsagePageVendor( 0x00                     ),
  HID_Usage          ( 0x01                     ),
  HID_Collection     ( HID_Application          ),
    HID_LogicalMin   ( 0                        ),  // value range: 0 - 0xFF
    HID_LogicalMaxS  ( 0xFF                     ),
    HID_ReportSize   ( 8                        ),  // 8 bits
    HID_ReportCount  ( HID_INPUT_REPORT_BYTES   ),
    HID_Usage        ( 0x01                     ),
    HID_Input        ( HID_Data | HID_Variable | HID_Absolute ),
    HID_ReportCount  ( HID_OUTPUT_REPORT_BYTES  ),
    HID_Usage        ( 0x01                     ),
    HID_Output       ( HID_Data | HID_Variable | HID_Absolute ),
    HID_ReportCount  ( HID_FEATURE_REPORT_BYTES ),
    HID_Usage        ( 0x01                     ),
    HID_Feature      ( HID_Data | HID_Variable | HID_Absolute ),
  HID_EndCollection,
};


In this thread, I explained the reason why such a simple descriptor is fine for vendor-specific HID implementation.
http://www.keil.com/forum/11793/

Ah, to extend the size of data to more than 255, up to 0xFFFF, replace "HID_ReportCount" macro into this one,
#define HID_ReportCountS(x)     0x96,((x)&0xFF),(((x)>>8)&0xFF)



Quote:
2). Which other functions will require modification?


The host application can send/receive 255 bytes of report in single call.
This report is split/gathered into 64 bytes (or less) transactions (packets) by the host controller, when the endpoint wMaxPacketSize is 64 bytes. And then, the HID device exchanges four transactions, 64, 64, 64, 63 bytes for every 255 bytes report.

As the example supposes just single transaction per report, you have to change the code flow intensively.

a) Output report (host --> device) over the interrupt OUT endpoint

In the first place, this example doesn't have the interrupt OUT endpoint.
This endpoint is added to the config descriptor set.
(1) Increase the wTotalLength field of Config descriptor by the size of the extra OUT endpoint
(2) Increase bNumEndpoints on the interface descriptor from 1 to 2
(3) additionally, increase the wMaxPacketSize to 64 bytes on the IN endpoint. Also, decrease the bInterval to 1 ms
(4) Append the OUT endpoint definition

usbdesc.c

const uint8_t USB_ConfigDescriptor[] = {
/* Configuration 1 */
  USB_CONFIGUARTION_DESC_SIZE,       /* bLength */
  USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */
  WBVAL(                             /* wTotalLength */
    USB_CONFIGUARTION_DESC_SIZE +
    USB_INTERFACE_DESC_SIZE     +
    HID_DESC_SIZE               +
    USB_ENDPOINT_DESC_SIZE * 2       // <---- (1)
  ),
  ...
/* Interface 0, Alternate Setting 0, HID Class */
  USB_INTERFACE_DESC_SIZE,           /* bLength */
  USB_INTERFACE_DESCRIPTOR_TYPE,     /* bDescriptorType */
  0x00,                              /* bInterfaceNumber */
  0x00,                              /* bAlternateSetting */
  0x02, /*0x01*/                     /* bNumEndpoints */     // <---- (2)
  ...
/* Endpoint, HID Interrupt In */
  USB_ENDPOINT_DESC_SIZE,            /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,      /* bDescriptorType */
  USB_ENDPOINT_IN(1),                /* bEndpointAddress */
  USB_ENDPOINT_TYPE_INTERRUPT,       /* bmAttributes */
  WBVAL(0x0040 /*0x0004*/),          /* wMaxPacketSize */    // <---- (3)
  1, /*0x20*/    /* 1ms */           /* bInterval */         // <---- (3)
                          // <---- (4) append the definition of interrupt OUT endpoint
/* Endpoint, HID Interrupt Out */
  USB_ENDPOINT_DESC_SIZE,            /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,      /* bDescriptorType */
  USB_ENDPOINT_OUT(1),               /* bEndpointAddress */
  USB_ENDPOINT_TYPE_INTERRUPT,       /* bmAttributes */
  WBVAL(0x0040),                     /* wMaxPacketSize */
  1,             /* 1ms */           /* bInterval */

/* Terminator */
  0                                  /* bLength */


Every time when an interrupt OUT transaction comes from host, USB_EndPoint1( USB_EVT_OUT ) callback is called. The OUT transactions are concatenated on OutReport[] buffer on this routine.
USB_Configure_Event() is a good place to initialize the endpoint context (variables and flags)
usbuser.c

#define HID_OUTPUT_SIZE    255

uint8_t  OutReport[ HID_OUTPUT_SIZE ];
uint32_t out_pos = 0;

void USB_EndPoint1 (uint32_t event) {
  uint32_t len;

  switch (event) {
    case USB_EVT_OUT:
      len = USB_ReadEP( USB_ENDPOINT_OUT(1), OutReport + out_pos );
      out_pos += len;
      if ( out_pos >= HID_OUTPUT_SIZE ) {
        out_pos = 0;
        //
        // the entire output report has been received
        // process it, here
        //
      }
      break;
      ...
  }
}


void USB_Configure_Event (void) {

  if (USB_Configuration) {                  /* Check if USB is configured */
    out_pos = 0;      // initialize interrupt OUT EP context
    ...
  }
}


b) Input report (device --> host) over the interrupt IN endpoint

The input report (255 bytes) is also split into 64 bytes (or less) transactions. Start_input_report_transfer() of this code sends the first transaction. Your firmware calls this routine, when it finishes to fill the input report on InReport[] buffer.

#define HID_IN_PACKET_SIZE  64
#define HID_INPUT_SIZE      255

uint8_t  InReport[ HID_INPUT_SIZE ];
uint32_t in_pos = 0;
bool     in_occupied = FALSE;

bool Start_input_report_transfer( void )
{
  if ( in_occupied ) return FALSE;
  in_occupied = TRUE;
  USB_WriteEP( USB_ENDPOINT_IN(1), InReport + in_pos, HID_IN_PACKET_SIZE );
  in_pos = HID_IN_PACKET_SIZE;
}

void USB_EndPoint1 (uint32_t event) {
  uint32_t len;

  switch (event) {
      ...
    case USB_EVT_IN:
      len = HID_INPUT_SIZE - in_pos;      // split the report into packets
      if ( len > HID_IN_PACKET_SIZE )  len = HID_IN_PACKET_SIZE;
                                          // send a packet to host
      USB_WriteEP( USB_ENDPOINT_IN(1), InReport + in_pos, len );
                                          // is the 
      in_pos += len;
      if ( in_pos >= HID_IN_PACKET_SIZE ) {
        in_pos = 0;
        in_occupied = FALSE;
      }
      break;
  }
}

void USB_Configure_Event (void) {

  if (USB_Configuration) {                  /* Check if USB is configured */
    ...
    in_pos = 0;      // initialize interrupt IN EP context
    in_occupied = FALSE;
  }
}


c) Input/output/feature report over the default endpoint
The stack code already has split/gather process for control transfer.
And then, you don't need to touch to it for large report.
But the example uses EP0Buf[] for the report exchange, which is assigned just 64 bytes.
You'll need to increase the buffer size.

usbcore.c
//uint8_t  EP0Buf[USB_MAX_PACKET0];
uint8_t  EP0Buf[HID_OUTPUT_SIZE];

usbcore.h
//extern uint8_t  EP0Buf[USB_MAX_PACKET0];
extern uint8_t  EP0Buf[HID_OUTPUT_SIZE];

Also, HID_GetReport() and HID_SetReport() in hiduser.c is coded just for single byte.
You'll modify these routines, so that they process the full report size (255 bytes).


Lastly, this example is also a BAD HID example, as I explained on this post
http://knowledgebase.nxp.com/showpost.php?p=27906&postcount=10

For practical HID implementation, the WriteEP() code in USB_Configure_Event() is not required.

Tsuneo
0 Kudos