Class Instance Concept

The USB classes available with the µC/USB-Device stack implement the concept of class instances. A class instance represents one function within a device. The function can be described by one interface or by a group of interfaces and belongs to a certain class.

Each USB class implementation has some configuration and functions in common based on the concept of class instance. The common configuration and functions are presented in Table - Constants and Functions Related to the Concept of Multiple Class Instances. In the column title 'Constants or Function', the placeholder XXXX can be replaced by the name of the class: AUDIO (Audio for function names), CDC, HID, MSC, PHDC or VENDOR (Vendor for function names).

Table - Constants and Functions Related to the Concept of Multiple Class Instances
Constant or functionDescription
USBD_XXXX_CFG_MAX_NBR_DEVConfigures the maximum number of class instances.
USBD_XXXX_CFG_MAX_NBR_CFG Configures the maximum number of configurations per device. During the class initialization, a created class instance will be added to one or more configurations.
USBD_XXXX_Add()Creates a new class instance.
USBD_XXXX_CfgAdd()Adds an existing class instance to the specified device configuration.


In terms of code implementation, the class will declare a local global table that contains a class control structure. The size of the table is determined by the constant USBD_XXXX_CFG_MAX_NBR_DEV. This class control structure is associated with one class instance and will contain certain information to manage the class instance. See the Class Instance Structures page for more details about this class control structure.

The following illustrations present several case scenarios. Each illustration is followed by a code listing showing the code corresponding to the case scenario. Figure - Multiple Class Instances - FS Device (1 Configuration with 1 Interface) represents a typical USB device. The device is Full-Speed (FS) and contains one single configuration. The function of the device is described by one interface composed of a pair of endpoints for the data communication. One class instance is created and it will allow you to manage the entire interface with its associated endpoint.

Figure - Multiple Class Instances - FS Device (1 Configuration with 1 Interface)

Multiple Class Instances - FS Device (1 Configuration with 1 Interface)


The code corresponding to Figure - Multiple Class Instances - FS Device (1 Configuration with 1 Interface) is shown in Listing - Multiple Class Instances - FS Device (1 Configuration with 1 Interface).

USBD_ERR    err;
CPU_INT08U  class_0;


USBD_XXXX_Init(&err);                                                                           (1)
if (err != USBD_ERR_NONE) {
    /* $$$$ Handle the error. */
}

class_0 = USBD_XXXX_Add(&err);                                                                  (2)
if (err != USBD_ERR_NONE) {
    /* $$$$ Handle the error. */
}

USBD_XXXX_CfgAdd(class_0, dev_nbr, cfg_0, &err);                                                (3)
if (err != USBD_ERR_NONE) {
    /* $$$$ Handle the error. */
}

(1) Initialize the class. Any internal variables, structures, and class Real-Time Operating System (RTOS) port will be initialized.

(2) Create the class instance, class_0. The function USBD_XXXX_Add() allocates a class control structure associated to class_0. Depending on the class, besides the parameter for an error code, USBD_XXXX_Add() may have additional parameters representing class-specific information stored in the class control structure.

(3) Add the class instance, class_0, to the specified configuration number, cfg_0USBD_XXXX_CfgAdd() will create the interface 0 and its associated endpoints IN and OUT. As a result, the class instance encompasses the interface 0 and its endpoints. Any communication done on the interface 0 will use the class instance number, class_0.


Figure - Multiple Class Instances - HS/FS Device (2 Configurations and 1 Single Interface) represents an example of a high-speed capable device. The device can support High-Speed (HS) and Full-Speed (FS). The device will contain two configurations: one valid if the device operates at full-speed and another if it operates at high-speed. In each configuration, interface 0 is the same but its associated endpoints are different. The difference will be the endpoint maximum packet size which varies according to the speed. If a high-speed host enumerates this device, by default, the device will work in high-speed mode and thus the high-speed configuration will be active. The host can learn about the full-speed capabilities by getting a Device_Qualifier descriptor followed by an Other_Speed_Configuration descriptor. These two descriptors describe a configuration of a high-speed capable device if it were operating at its other possible speed (refer to Universal Serial Bus 2.0 Specification revision 2.0, section 9.6, for more details about these descriptors). In our example, the host may want to reset and enumerate the device again in full-speed mode. In this case, the full-speed configuration is active. Whatever the active configuration, the same class instance is used. Indeed, the same class instance can be added to different configurations. A class instance cannot be added several times to the same configuration.

Figure - Multiple Class Instances - HS/FS Device (2 Configurations and 1 Single Interface)


The code corresponding to Figure - Multiple Class Instances - HS/FS Device (2 Configurations and 1 Single Interface) is shown in Listing - Multiple Class Instances - HS/FS Device (2 Configurations and 1 Single Interface).

USBD_ERR    err;
CPU_INT08U  class_0;


USBD_XXXX_Init(&err);                                                                           (1)
if (err != USBD_ERR_NONE) {
    /* $$$$ Handle the error. */
}

class_0 = USBD_XXXX_Add(&err);                                                                  (2)
if (err != USBD_ERR_NONE) {
    /* $$$$ Handle the error. */
}

USBD_XXXX_CfgAdd(class_0, dev_nbr, cfg_0_fs, &err);                                             (3)
if (err != USBD_ERR_NONE) {
    /* $$$$ Handle the error. */
}

USBD_XXXX_CfgAdd(class_0, dev_nbr, cfg_0_hs, &err);                                             (4)
if (err != USBD_ERR_NONE) {
    /* $$$$ Handle the error. */
}

(1) Initialize the class. Any internal variables, structures, and class RTOS port will be initialized.

(2) Create the class instance, class_0. The function USBD_XXXX_Add() allocates a class control structure associated to class_0. Depending on the class, besides the parameter for an error code, USBD_XXXX_Add() may have additional parameters representing class-specific information stored in the class control structure.

(3) Add the class instance, class_0, to the full-speed configuration, cfg_0_fs. USBD_XXXX_CfgAdd() will create the interface 0 and its associated endpoints IN and OUT. If the full-speed configuration is active, any communication done on the interface 0 will use the class instance number, class_0.

(4) Add the class instance, class_0, to the high-speed configuration, cfg_0_hs.


In the case of the high-speed capable device presented in Figure - Multiple Class Instances - HS/FS Device (2 Configurations and 1 Single Interface), in order to enable the use of Device_Qualifier and Other_Speed_Configuration descriptors, the function USBD_CfgOtherSpeed() should be called during the µC/USB-Device initialization. Listing - App_USBD_Init() Function presents the function App_USBD_Init() defined in app_usbd.c. This function shows an example of the µC/USB-Device initialization sequence. USBD_CfgOtherSpeed() should be called after the creation of a high-speed and a full-speed configurations with USBD_CfgAdd()Listing - Use of USBD_CfgOtherSpeed() below shows the use of USBD_CfgOtherSpeed() based on Listing - App_USBD_Init() Function. Error handling is omitted for clarity.

 CPU_BOOLEAN  App_USBD_Init (void)
{
    CPU_INT08U   dev_nbr;
    CPU_INT08U   cfg_0_fs;
    CPU_INT08U   cfg_0_hs;
    USBD_ERR     err;


    ...                                                                                         (1)
 
    if (USBD_DrvCfg_<controller>.Spd == USBD_DEV_SPD_HIGH) {
 
        cfg_0_hs = USBD_CfgAdd(dev_nbr,                                                         (2)
                               USBD_DEV_ATTRIB_SELF_POWERED,
                               100u,
                               USBD_DEV_SPD_HIGH,
                              "HS configuration",
                              &err);	
    }
    cfg_0_fs = USBD_CfgAdd(dev_nbr,                                                             (3)
                           USBD_DEV_ATTRIB_SELF_POWERED,
                           100u,
                           USBD_DEV_SPD_FULL,
                          "FS configuration",
                          &err);
    
    USBD_CfgOtherSpeed(dev_nbr,                                                                 (4)
                       cfg_0_hs,
                       cfg_0_fs,
                      &err);

    return (DEF_OK);
}

(1) Refer to Listing - App_USBD_Init() Function for the beginning of the initialization.

(2) Add the high-speed configuration, cfg_0_hs, to your high-speed capable device.

(3) Add the full-speed configuration, cfg_0_fs, to your high-speed capable device.

(4) Associate the high-speed configuration cfg_0_hs with its other-speed counterpart, cfg_0_fs.


Figure - Multiple Class Instances - FS Device (2 Configurations and Multiple Interfaces) represents a more complex example. A full-speed device is composed of two configurations. The device has two functions which belong to the same class. Each function is described by two interfaces. Each interface has a pair of bidirectional endpoints. In this example, two class instances are created. Each class instance is associated with a group of interfaces as opposed to Figure - Multiple Class Instances - FS Device (1 Configuration with 1 Interface) and Figure - Multiple Class Instances - HS/FS Device (2 Configurations and 1 Single Interface) where the class instance was associated to a single interface.

Figure - Multiple Class Instances - FS Device (2 Configurations and Multiple Interfaces)

Multiple Class Instances - FS Device (2 Configurations and Multiple Interfaces)


The code corresponding to Figure - Multiple Class Instances - FS Device (2 Configurations and Multiple Interfaces) is shown in Listing - Multiple Class Instances - FS Device (2 Configurations and Multiple Interfaces). The error handling is omitted for clarity.

USBD_ERR    err;
CPU_INT08U  class_0;
CPU_INT08U  class_1;


USBD_XXXX_Init(&err);                                                                           (1)

class_0 = USBD_XXXX_Add(&err);                                                                  (2)
class_1 = USBD_XXXX_Add(&err);                                                                  (3)

USBD_XXXX_CfgAdd(class_0, dev_nbr, cfg_0, &err);                                                (4)
USBD_XXXX_CfgAdd(class_1, dev_nbr, cfg_0, &err);                                                (5)

USBD_XXXX_CfgAdd(class_0, dev_nbr, cfg_1, &err);                                                (6)
USBD_XXXX_CfgAdd(class_1, dev_nbr, cfg_1, &err);                                                (6)

(1) Initialize the class. Any internal variables, structures, and class RTOS port will be initialized.

(2) Create the class instance, class_0. The function USBD_XXXX_Add() allocates a class control structure associated to class_0.

(3) Create the class instance, class_1. The function USBD_XXXX_Add() allocates another class control structure associated to class_1.

(4) Add the class instance, class_0, to the configuration, cfg_0. USBD_XXXX_CfgAdd() will create the interface 0, interface 1, alternate interfaces, and the associated endpoints IN and OUT. The class instance number, class_0, will be used for any data communication on interface 0 or interface 1.

(5) Add the class instance, class_1, to the configuration, cfg_0. USBD_XXXX_CfgAdd() will create the interface 2, interface 3 and their associated endpoints IN and OUT. The class instance number, class_1, will be used for any data communication on interface 2 or interface 3.

(6) Add the same class instances, class_0 and class_1, to the other configuration, cfg_1.