Migration notes -
Microchip USB firmware framework
1.1.1. HID feature report functions
1.2.1. Host Client Driver Modifications
1.2.2. HID Client Driver Modifications
2.2. USB_NUM_STRING_DESCRIPTORS
3.4. Project – Include options
requirement
3.7. API changes - Using handles
3.8.2. Buffer location - Sending data
from user space
In previous revisions of the stack the HIDGetReportHandler and HIDSetReportHandler were hollow functions that the user needed to fill out in the usb_function_hid.c file. This interface has changed. The user will now define USER_GET_REPORT_HANDLER with the function that needs to be called when a get report request is received. This should be defined in usb_config.h. Likewise USER_SET_REPORT_HANDLER should be defined to point to the function that will handle a set report request.
For example:
usb_config.h:
#define
USER_GET_REPORT_HANDLER UserGetReportHandler
#define USER_SET_REPORT_HANDLER UserSetReportHandler
main.c
void UserGetReportHandler(void)
{
//handle request here
}
There are two changes in the USB Host Stack to provide better support for applications that communicate with composite USB devices. Most USB devices require only a single client driver to provide an interface to the device. A composite device requires multiple client drivers, all active at the same time. This previously caused problems if both client drivers required transfers on Endpoint 0. The changes below account for this requirement.
These changes affect all Client Drivers for the Host. All Client Drivers that ship with the USB Host Stack have already been modified. Any custom client drivers will require slight modification, as described below.
1. The Initialization Handler prototype has been modified to include a client driver identifier:
BOOL (*USB_CLIENT_INIT)(
BYTE address, DWORD flags, BYTE clientDriverID )
The new clientDriverID parameter is an input parameter. The client driver must retain this value for use when issuing Device Requests.
2. The API function USBHostDeviceRequest() has been removed. It has been replaced by the function :
BYTE
USBHostIssueDeviceRequest( BYTE deviceAddress, BYTE bmRequestType, BYTE bRequest,
WORD wValue, WORD wIndex,
WORD wLength, BYTE *data, BYTE dataDirection,
BYTE clientDriverID )
The only difference between these two functions is that the new USBHostIssueDeviceRequest() function has the additional clientDriverID parameter. The value of this input parameter should be the same as the value of the clientDriverID received by the Initialization Handler.
These changes affect only the Client Drivers. They will be transparent to the application layer.
In addition to the general client driver modifications described above, the HID client driver has several modifications.
1. The files usb_host_hid_appl_interface.c and usb_host_hid_appl_interface.h have been removed. These files should be removed from any existing projects.
2. Duplicate functions have been consolidated. Macros have been added for backward compatibility, but new applications should use the new functions. The following functions have been replaced:
a. USBHostHID_ApiDeviceDetect() – Use USBHostHIDDeviceDetect(). An additional deviceAddress parameter is required.
b. USBHostHID_ApiGetReport() - Use USBHostHIDRead(). An additional deviceAddress parameter is required.
c. USBHostHID_ApiSendReport() – Use USBHostHIDWrite(). An additional deviceAddress parameter is required.
d. USBHostHID_ApiResetDevice() – Use USBHostHIDResetDeviceWithWait(). An additional deviceAddress parameter is required.
e. USBHostHID_ApiTransferIsComplete() – Use USBHostHIDTransferIsComplete(). An additional deviceAddress parameter is required.
3. Events from the HID Client Driver will now be sent to the application layer. Key events are:
a. EVENT_HID_ATTACH - This is a new event, notifying the application layer that a HID device is attached. The returned data pointer points to a USB_HID_DEVICE_ID structure. The application should retain this information for future communication with the device.
b. EVENT_HID_DETACH – This is a new event, notifying the application layer that a HID device has detached. The returned data pointer points to a byte with the previous address of the detached device.
c. EVENT_HID_RPT_DESC_PARSED – The application must handle this event. The client driver sends this event after the Report Descriptor has been parsed, so the application layer can retrieve and validate its information. If the application can utilize the device with the specified Report Descriptor, or if it is already aware of the data format, it must return TRUE. If the application encounters a problem, it must return FALSE. In previous versions, the application function that performs this function is captured by the configuration tool USBConfig.exe as the “Parsed Data Collection handler”. Now, simply add this event to the application’s event handler, call this function, and have the event handler return the function’s return value.
d. EVENT_HID_READ_DONE – If transfer events are enabled from the HID layer, this event will be returned when a read operation completes.
4. A transfer termination function has been added. If a device uses endpoint 0 for OUT transfers (host to device), control transfers are used rather than interrupt transfers. The termination mechanisms are different for control transfers, so the application may have to manually terminate the transfer after a certain time-out period. The prototype for this function is:
BYTE USBHostHIDTerminateTransfer( BYTE deviceAddress, BYTE
direction, BYTE interfaceNum );
5. To clean up unused data elements, run the configuration tool USBConfig.exe to regenerate the usb_config.c and usb_config.h configuration files. This is not required, but it will remove unnecessary data.
With
the introduction of the interrupt driven option of the stack there are some
compile time options available to select the functionality in regards to how
the stack notifies users of events in the stack.
To support interrupts using the legacy callback
functions in v2.3 define the following definition in usb_config.h:
#define USB_INTERRUPT_LEGACY_CALLBACKS
This will cause the stack to call the
callback functions directly when the event occurs.
Because
it is not always desirable to get every single event for CPU usage reasons,
definitions have been created in order to enable the desired events.
The
USB_ENABLE_ALL_HANDLERS can be defined in usb_config.h
to enable all of the events.
If
only certain events are desired then the following definitions can be made in
the usb_config.h file to enable those features.
#define
USB_ENABLE_SUSPEND_HANDLER
#define
USB_ENABLE_WAKEUP_FROM_SUSPEND_HANDLER
#define
USB_ENABLE_SOF_HANDLER
#define
USB_ENABLE_ERROR_HANDLER
#define
USB_ENABLE_OTHER_REQUEST_HANDLER
#define
USB_ENABLE_SET_DESCRIPTOR_HANDLER
#define
USB_ENABLE_INIT_EP_HANDLER
#define
USB_ENABLE_EP0_DATA_HANDLER
#define
USB_ENABLE_TRANSFER_COMPLETE_HANDLER
The
USB_NUM_STRING_DESCRIPTORS has been added as a required definition to the usb_config.h file.
This number should indicate the total number of USB strings that are in
the string descriptors array, including the language string descriptors.
Take
the following example:
//Language
code string descriptor
ROM
struct{BYTE
bLength;BYTE bDscType;WORD
string[1];}sd000={
sizeof(sd000),USB_DESCRIPTOR_STRING,{0x0409
}};
//Manufacturer
string descriptor
ROM
struct{BYTE
bLength;BYTE bDscType;WORD
string[25];}sd001={
sizeof(sd001),USB_DESCRIPTOR_STRING,
{'M','i','c','r','o','c','h','i','p',' ',
'T','e','c','h','n','o','l','o','g','y',' ','I','n','c','.'
}};
//Product
string descriptor
ROM
struct{BYTE
bLength;BYTE bDscType;WORD
string[22];}sd002={
sizeof(sd002),USB_DESCRIPTOR_STRING,
{'K','e','y','b','o','a','r','d',' ','D','e','m','o'
}};
//Array
of string descriptors
ROM
BYTE *ROM USB_SD_Ptr[]=
{
(ROM BYTE *ROM)&sd000,
(ROM BYTE *ROM)&sd001,
(ROM BYTE *ROM)&sd002
};
In this example the
USB_NUM_STRING_DESCRIPTORS should be defined as 3, matching the size of the USB_SD_Ptr array.
The directory structure of the USB firmware framework
has changed from the v1.x releases. This
change helps simplify the process of combining several of the other software
solutions provided by Microchip. The new
directory structure also helps designate which files are part of user code and
which files are part of the stack. The new directory structure looks like the
following. Note that the stack is no
longer required to be installed in the MCHPFSUSB folder in the root directory.
.\<Install Directory>
\Microchip
\Include
\Help
\USB
\Documentation
\USB Device
- Bootloaders
\USB Device
– HID - Mouse
\USB Device
– HID – Simple Custom Demo
\USB Device
– Mass Storage – SD Card data logger
\USB Device
– Mass Storage – SD Card reader
\USB Device
– MCHPUSB - Generic Driver Demo
\USB Host –
Mass Storage - Data Logger
\USB PC –
WM_DEVICECHANGE Demo
\USB
Precompiled Demos
\USB Tools
The “<Install Directory>\Microchip” folder
contains the stack and documentation required to design a USB application. Also contained in the “<Install
Directory>” are several example projects.
The “<Install Directory>\USB Tools” contains
some PC software tools. This directory
contains the Microchip custom driver, the driver source code, and a couple of
PC examples how to link the driver into PC software. This folder also contains the configuration
tool required for generating the embedded host configuration files required to
run the stack.
The “<Install
Directory>\Microchip\USB\Documentation” contains documentation for using the
demos, release notes, and other documentation pertaining to the release and
tools available.
The “<Install Directory>\Microchip\Help” folder
contains .chm help files that describe in detail the
API of the embedded host stack. If you
have installed other Microchip libraries into the same <Install
Directory> then there may be other help files located in the directory.
The
usb_config.h file contains definitions that determine
how the stack will function. This file
defines if the device stack or the host stack will be enabled, what ping-pong
configuration is used, which class drivers are enabled, and various other
options. Please review the example
configuration files for more details about the options available. The usb_config.h
file for embedded host applications is generated by the USBConfig.exe tool
provided in the “<Install Directory>\Microchip\USB\Utilities\USBConfig” folder.
For
many of the examples the hardware configuration is different for each of the
hardware platforms available. The HardwareProfile.h file helps abstract out the hardware
differences. This file defines which
board is being used based on the processor selected in MPLAB. When using the stack to develop new applications,
it is important to change the HardwareProfile.h file
to use custom boards. This can be done
by either removing the predefined settings or by adding a definition for DEMO_BOARD at the top of the file.
Because
of the changes in the directory structure, there are some changes that are
required in the “Project->Build Options->Project” include path
settings. The following paths need to be
added to the include path:
..\Include
..\..\Include
..\Microchip\Include
..\..\<Application
Folder>
..\..\..\<Application
Folder>
Here
are the settings used for one of the example projects:
If
the project and source files are not located in the <Install Directory>\<Application
Folder> but instead of folder like <Install
Directory>\<Folder>\<Application Folder> then the above include
paths need to be changed so that each have one more “..\” and that the two
includes that are using the <Application Folder> also include the
additional <Folder> in their path.
For example:
..\..\Include
..\..\..\Include
..\..\Microchip\Include
..\..\<Folder>\<Application
Folder>
..\..\..\<Folder>\<Application
Folder>
The
v2.1 stack has several call back functions that need to be defined in the user
code. These functions are provided to
allow the user to define their course of action when certain USB events occur
without having to modify the stack code itself.
The following functions need to be defined.
void USBCBSuspend(void)
void USBCBWakeFromSuspend(void)
void USBCB_SOF_Handler(void)
void USBCBErrorHandler(void)
void USBCBCheckOtherReq(void)
void USBCBStdSetDscHandler(void)
void USBCBInitEP(void)
void USBCBSendResume(void)
Some
of the device classes require the use of the endpoint 0. These functions may require the use of the USBCBCheckOtherReq() function to call back into the device driver code. For an example of this use, review any of the
Mass Storage examples.
All
applications will need to take action in the USBCBSuspend() and USBCBWakeFromSuspend() functions in order to insure they meet the maximum
current requirements during suspend.
The
USBCBInitEP() is also required by all
of the class drivers to enable the endpoints that they use. This can be done with the USBEnableEndpoint() function. Any IN endpoints not only need to enable the
endpoints but also need to arm the IN endpoints so that they are ready to
receive data in that input. Enabling the
endpoint can be done using the class specific functions.
As
mentioned in the above call back functions section, it is important that the
user device in the USBCBInitEP() function the appropriate
endpoint enable functions. It is also
important to enable any IN endpoints.
This allows the endpoint to be ready to receive data as soon as the host
sends a transaction to that endpoint.
Please see the provided demo projects.
The
v2.x USB stack defines the concept of a USB_HANDLE. The handle
is used to determine if a transfer is complete.
A handle is returned for each transmission sent out. If ping-pong is enabled this means that two
handles per endpoint and direction combination are possible. Each handle should be saved to a different
variable so each can be checked independently.
To
check to see if a transfer complete, pass the handle to the USBHandleBusy() function.
This function will return FALSE
if the transfer is still in process and TRUE if the transfer is complete. The
class driver specific transmit and receive functions should return the USB_HANDLE. For example:
USB_HANDLE USBGenericInHandle = 0;
if(!USBHandleBusy(USBGenericInHandle))
{
//Transfer counter bytes of data from INPacket on endpoint USBGEN_EP_NUM
USBGenericInHandle = USBGenWrite(USBGEN_EP_NUM,(BYTE*)&INPacket,counter);
}
There are some very specific changes to the Microchip
Generic class driver code as provided that need to be highlighted.
In
the 1.x releases of the USB firmware framework the transferred and received
data was buffered in the device class layer.
This allowed users to send data to the computer and immediately start
refilling the buffer without having to wait for the original transfer to
complete.
With
release of the 2.x version USB framework, the buffering of the data transferred
has been removed. This means that
applications that can’t wait until the previous transfer is complete must
double buffer the data in the application layer. The data is now transferred directly from the
user buffer.
As
stated in the previous section “Data buffering removed”, the data transferred
by the generic driver is no longer buffered in the class driver. The combination of sending data from the user
data space and the limited USB dual port RAM on the PIC18F4550, PIC18F4450, and
PIC18F4553 families, the user needs to be able to reuse as much of the dual
port RAM as possible. Since the BDT
usage changes based on the number of endpoints use and the ping-pong mode
selected, the end address of the BDT may not be easily calculated. This modification is not required for the
PIC18F87J50 or PIC24J256GB110 family devices.
In order to allocate user data in the same section as the BDT, use the #pragma directive and define a section name that the user
variables should be located at. For
example:
#pragma udata USB_VARS
DATA_PACKET INPacket;
DATA_PACKET OUTPacket;
#pragma udata
This
locates these two variables in the USB_VARS section. This is only one half of the equation. Without a specific address the linker will
ignore the #pramga definition and define the variable
wherever it finds room. The second step
is to define where the USB_VARS section is located. This modification is made in the linker file
for specific device. At the end of the
linker file add a line that defines what section of RAM the variables are
located in. For example:
SECTION NAME=USB_VARS RAM=usb4
The
“usb4” section name in this case is the name defined in the linker file:
ACCESSBANK NAME=accessram START=0x0 END=0x5F
DATABANK NAME=gpr0 START=0x60 END=0xFF
DATABANK NAME=gpr1 START=0x100 END=0x1FF
DATABANK NAME=gpr2 START=0x200 END=0x2FF
DATABANK NAME=gpr3 START=0x300 END=0x3FF
DATABANK NAME=usb4 START=0x400 END=0x4FF PROTECTED
DATABANK NAME=usb5 START=0x500 END=0x5FF PROTECTED
DATABANK NAME=usb6 START=0x600 END=0x6FF PROTECTED
DATABANK NAME=usb7 START=0x700 END=0x7FF PROTECTED
ACCESSBANK NAME=accesssfr START=0xF60 END=0xFFF PROTECTED
SECTION NAME=CONFIG ROM=config
STACK SIZE=0x100 RAM=gpr3
The
format of the configuration descriptor was changed from a structure to a byte
array. This removes the requirement of
having to modify a configuration descriptor structure definition to add
information to the configuration descriptor.
This, however, creates a situation where entries that were previously
added to the structure now need to be add as
individual bytes. Please be aware that
configuration descriptors created for the v1.x stack will need to be converted
to this new format by splitting up the word or larger entries manually or using
the assistance macros discussed later in this section. For example:
Old
entry:
0x55,
0xAAFF,
0x11,…
New
entry:
0x55,
0xFF,0xAA,
0x11,…
To
help the conversion and to help make the code more readable, an optional macro
named DESC_CONFIG_WORD() as been added that does this
split automatically. DESC_CONFIG_BYTE() and DESC_CONFIG_DWORD() have been added for
consistency. For example:
New
entry:
0x55,
DESC_CONFIG_WORD(0xAAFF),
0x11,…
--
Or --
New
entry:
DESC_CONFIG_BYTE(0x55),
DESC_CONFIG_WORD(0xAAFF),
DESC_CONFIG_BYTE(0x11),…
The Microchip name and logo, the Microchip logo,
MPLAB, and PIC are registered trademarks of Microchip Technology Incorporated
in the
PICDEM is a trademark of
Microchip Technology Incorporated in the
Microsoft, Windows, and Windows
Vista are either registered trademarks or trademarks of Microsoft Corporation
in the
Borland, and C++ Builder
are trademarks or registered trademarks of Borland Software Corporation in the
Linux is the registered trademark of Linus Torvalds in the