Migration notes - Microchip USB firmware framework

 

1.     v2.4 to v2.5

1.1.      Device Stack Changes

1.1.1.       HID feature report functions

1.2.      Host Stack Changes

1.2.1.       Host Client Driver Modifications

1.2.2.       HID Client Driver Modifications

2.     v2.3 to v2.4

2.1.      Callback Mechanism

2.2.      USB_NUM_STRING_DESCRIPTORS

3.     v1.x to v2.x

3.1.      Directory Structure

3.2.      usb_config.h

3.3.      HardwareProfile.h

3.4.      Project – Include options requirement

3.5.      Call back functions

3.6.      Enabling endpoints

3.7.      API changes - Using handles

3.8.      Generic Driver

3.8.1.       Data buffering removed

3.8.2.       Buffer location - Sending data from user space

3.9.      Configuration Descriptor

Trademarks:

 

1.    v2.4 to v2.5

1.1.                    Device Stack Changes

1.1.1.HID feature report functions

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

                                    }

 

1.2.                    Host Stack Changes

1.2.1.Host Client Driver Modifications

 

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.

 

1.2.2.HID Client Driver Modifications

 

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.

 

2.    v2.3 to v2.4

2.1.                    Callback Mechanism

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

 

2.2.                    USB_NUM_STRING_DESCRIPTORS

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.

3.    v1.x to v2.x

3.1.                    Directory Structure

 

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.

3.2.                    usb_config.h

 

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.

3.3.                    HardwareProfile.h

 

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.

3.4.                    Project – Include options requirement

 

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>

 

3.5.                    Call back functions

 

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.

3.6.                    Enabling endpoints

 

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.

3.7.                    API changes - Using handles

 

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);

}

 

3.8.                    Generic Driver

 

There are some very specific changes to the Microchip Generic class driver code as provided that need to be highlighted. 

3.8.1.   Data buffering removed

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. 

3.8.2.   Buffer location - Sending data from user space

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

 

3.9.                    Configuration Descriptor

 

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),…

 

 

Trademarks:

The Microchip name and logo, the Microchip logo, MPLAB, and PIC are registered trademarks of Microchip Technology Incorporated in the U.S.A. and other countries.

PICDEM is a trademark of Microchip Technology Incorporated in the U.S.A. and other countries.

Microsoft, Windows, and Windows Vista are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries.

Borland, and C++ Builder are trademarks or registered trademarks of Borland Software Corporation in the United States and other countries.

Linux is the registered trademark of Linus Torvalds in the U.S. and other countries.