ACM Subclass

The ACM subclass is used by two types of communication devices:

  • Devices supporting AT commands (for instance, voiceband modems).
  • Serial emulation devices which are also called Virtual COM port devices.

Micrium’s ACM subclass implementation complies with the following specification:

  • Universal Serial Bus, Communications, Subclass for PSTN Devices, revision 1.2, February 9, 2007.

Overview

The general characteristics of the CDC base class in terms of Communications Class Interface (CCI) and Data Class Interface (DCI) were presented in the CDC Class Overview page. In this section, a CCI of type ACM is considered. It will consist of a default endpoint for the management element and an interrupt endpoint for the notification element. A pair of bulk endpoints is used to carry unspecified data over the DCI.

Several subclass-specific requests exists for the ACM subclass. They allow you to control and configure the device. The complete list and description of all ACM requests can be found in the specification “Universal Serial Bus, Communications, Subclass for PSTN Devices, revision 1.2, February 9, 2007”, section 6.2.2. From this list, Micrium’s ACM subclass supports:

Table - ACM Requests Supported by Micrium
Subclass requestDescription
SetCommFeatureThe host sends this request to control the settings for a particular communications feature. Not used for serial emulation.
GetCommFeatureThe host sends this request to get the current settings for a particular communications feature. Not used for serial emulation.
ClearCommFeatureThe host sends this request to clear the settings for a particular communications feature. Not used for serial emulation.
SetLineCodingThe host sends this request to configure the ACM device settings in terms of baud rate, number of stop bits, parity type and number of data bits. For a serial emulation, this request is sent automatically by a serial terminal each time you configure the serial settings for an open virtual COM port.
GetLineCodingThe host sends this request to get the current ACM settings (baud rate, stop bits, parity, data bits). For a serial emulation, serial terminals send this request automatically during virtual COM port opening.
SetControlLineStateThe host sends this request to control the carrier for half duplex modems and indicate that Data Terminal Equipment (DTE) is ready or not. In the serial emulation case, the DTE is a serial terminal. For a serial emulation, certain serial terminals allow you to send this request with the controls set.
SetBreakThe host sends this request to generate an RS-232 style break. For a serial emulation, certain serial terminals allow you to send this request.


Micrium’s ACM subclass uses the interrupt IN endpoint to notify the host about the current serial line state. The serial line state is a bitmap informing the host about:

  • Data discarded because of overrun
  • Parity error
  • Framing error
  • State of the ring signal detection
  • State of break detection mechanism
  • State of transmission carrier
  • State of receiver carrier detection

Configuration

Table - ACM Serial Emulation Subclass Configuration Constants shows the constant available to customize the ACM serial emulation subclass. This constant is located in the USB device configuration file, usbd_cfg.h.

Table - ACM Serial Emulation Subclass Configuration Constants
ConstantDescriptionPossible Values
USBD_ACM_SERIAL_CFG_MAX_NBR_DEVConfigures the maximum number of subclass instances. The constant value cannot be greater than USBD_CDC_CFG_MAX_NBR_DEV. Unless you plan on having multiple configurations or interfaces using different class instances, this can be set to the default value.From 1 to USBD_CDC_CFG_MAX_NBR_DEV. Default value is 1.


Subclass Instance Configuration

Before starting the communication phase, your application needs to initialize and configure the class to suit its needs.  Table - ACM Subclass Initialization API Summary summarizes the initialization functions provided by the ACM subclass. For more details about the functions’ parameters, refer to the CDC ACM Subclass Functions reference.

Table - ACM Subclass Initialization API Summary
Function nameOperation
USBD_ACM_SerialInit()Initializes ACM subclass internal structures and variables.
USBD_ACM_SerialAdd()Creates a new instance of ACM subclass.
USBD_ACM_SerialCfgAdd()Adds an existing ACM instance to the specified device configuration.
USBD_ACM_SerialLineCodingReg()Registers line coding notification callback.
USBD_ACM_SerialLineCtrlReg()Registers line control notification callback.


You need to call these functions in the order shown below to successfully initialize the ACM subclass:

  1. Call USBD_ACM_SerialInit() 
    This function initializes all internal structures and variables that the ACM subclass needs. You should call this function only once even if you use multiple class instances.
  2. Call USBD_ACM_SerialAdd() 
    This function allocates an ACM subclass instance. Internally, this function allocates a CDC class instance. It also allows you to specify the line state notification interval expressed in milliseconds and the Call Management capabilities.
  3. Call USBD_ACM_SerialLineCodingReg() 
    This function allows you to register a callback used by the ACM subclass to notify the application about a change in the serial line coding settings (that is baud rate, number of stop bits, parity and number of data bits).
  4. Call USBD_ACM_SerialLineCtrlReg() 
    This function allows you to register a callback used by the ACM subclass to notify the application about a change in the serial line state (that is RS-232 break signal, carrier control, i.e. RS-232 RTS signal, and a flag indicating that data equipment terminal is present or not, i.e. RS-232 DTR signal,).
  5. Call USBD_ACM_SerialCfgAdd() 
    Finally, once the ACM subclass instance has been created, you must add it to a specific configuration.

Listing - CDC ACM Subclass Initialization Example illustrates the use of the previous functions for initializing the ACM subclass. Note that the error handling has been omitted for clarity.

CPU_BOOLEAN  App_USBD_CDC_Init (CPU_INT08U  dev_nbr,
                                CPU_INT08U  cfg_hs,
                                CPU_INT08U  cfg_fs)
{
    USBD_ERR    err;
    CPU_INT08U  subclass_nbr;


    USBD_CDC_Init(&err);                                                      (1)

    USBD_ACM_SerialInit(&err);                                                (2)
                                                                              (3)
    subclass_nbr = USBD_ACM_SerialAdd(64u,
                                     (USBD_ACM_SERIAL_CALL_MGMT_DATA_CCI_DCI | USBD_ACM_SERIAL_CALL_MGMT_DEV),
                                     &err);

    USBD_ACM_SerialLineCodingReg(        subclass_nbr,                        (4)
                                         App_USBD_CDC_SerialLineCoding,
                                 (void *)0,
                                        &err);

    USBD_ACM_SerialLineCtrlReg(        subclass_nbr,                          (5)
                                       App_USBD_CDC_SerialLineCtrl,
                               (void *)0,
                                      &err);

    if (cfg_hs != USBD_CFG_NBR_NONE) {
        USBD_ACM_SerialCfgAdd(subclass_nbr, dev_nbr, cfg_hs, &err);           (6)
    }

    if (cfg_fs != USBD_CFG_NBR_NONE) {
        USBD_ACM_SerialCfgAdd(subclass_nbr, dev_nbr, cfg_fs, &err);           (7)
    }
}

(1) Initialize CDC internal structures and variables.

(2) Initialize CDC ACM internal structures and variables.

(3) Create a new CDC ACM subclass instance. In this example, the line state notification interval is 64 ms. In the CCI, an interrupt IN endpoint is used to asynchronously notify the host of the status of the different signals forming the serial line. The line state notification interval corresponds to the interrupt endpoint’s polling interval. The second argument allows to specify the Call Management support of the CDC ACM function. In this example, the device handles the call management itself (USBD_ACM_SERIAL_CALL_MGMT_DEV) and information can be set over a DCI (USBD_ACM_SERIAL_CALL_MGMT_DATA_CCI_DCI).

Mac OS X supports only all combinations of the call management capabilities except: (USBD_ACM_SERIAL_CALL_MGMT_DEV). For this latter combination, Mac OS X won't recognize the CDC ACM function. Windows and Linux operating systems accept any combinations of the flags. See USBD_ACM_SerialAdd() for more details about the possible flags combinations.

(4) Register the application callback, App_USBD_CDC_SerialLineCoding(). It is called by the ACM subclass when the class-specific request SET_LINE_CODING has been received by the device. This request allows the host to specify the serial line settings (baud rate, stop bits, parity and data bits). Refer to “CDC PSTN Subclass, revision 1.2”, section 6.3.10 for more details about this class-specific request.

(5) Register the application callback, App_USBD_CDC_SerialLineCtrl(). It is called by the ACM subclass when the class-specific request SET_CONTROL_LINE_STATE has been received by the device. This request generates RS-232/V.24 style control signals. Refer to “CDC PSTN Subclass, revision 1.2”, section 6.3.12 for more details about this class-specific request.

(6) Check if the high-speed configuration is active and proceed to add the ACM subclass instance to this configuration.

(7) Check if the full-speed configuration is active and proceed to add the ACM subclass instance to this configuration.


Listing - CDC ACM Subclass Initialization Example also illustrates an example of multiple configurations. The functions USBD_ACM_SerialAdd() and USBD_ACM_SerialCfgAdd() allow you to create multiple configurations and multiple instances architecture. Refer to the Class Instance Concept page for more details about multiple class instances.

Subclass Notification and Management

You have access to some functions provides in the ACM subclass which relate to the ACM requests and the serial line state previously presented in the Overview section.  shows these functions. Refer to the CDC ACM Subclass Functions reference for more details about the functions’ parameters.

Table - ACM Subclass Functions Related to the Subclass Requests and Notifications
FunctionRelates to...Description
USBD_ACM_SerialLineCodingGet()SetLineCodingApplication can get the current line coding settings set either by the host with SetLineCoding requests or by USBD_ACM_SerialLineCodingSet()
USBD_ACM_SerialLineCodingSet()GetLineCodingApplication can set the line coding. The host can retrieve the settings with the GetLineCoding request.
USBD_ACM_SerialLineCodingReg()SetLineCodingApplication registers a callback called by the ACM subclass upon reception of the SetLineCoding request. Application can perform any specific operations.
USBD_ACM_SerialLineCtrlGet()SetControlLineStateApplication can get the current control line state set by the host with the SetControlLineState request.
USBD_ACM_SerialLineCtrlReg()

SendBreak

SetControlLineState

Application registers a callback called by the ACM subclass upon reception of the SendBreak or SetControlLineState requests. Application can perform any specific operations.
USBD_ACM_SerialLineStateSet()Serial line stateApplication can set any line state event(s). While setting the line state, an interrupt IN transfer is sent to the host to inform about it a change in the serial line state.
USBD_ACM_SerialLineStateClr()Serial line stateApplication can clear two events of the line state: transmission carrier and receiver carrier detection. All the other events are self-cleared by the ACM serial emulation subclass.


Micrium’s ACM subclass always uses the interrupt endpoint to notify the host of the serial line state. You cannot disable the interrupt endpoint.

Subclass Instance Communication

Micrium’s ACM subclass offers the following functions to communicate with the host. For more details about the functions’ parameters, refer to the CDC ACM Subclass Functions reference.

Table - CDC ACM Communication API Summary
Function nameOperation
USBD_ACM_SerialRx()Receives data from host through a bulk OUT endpoint. This function is blocking.
USBD_ACM_SerialTx()Sends data to host through a bulk IN endpoint. This function is blocking.


USBD_ACM_SerialRx() and USBD_ACM_SerialTx() provide synchronous communication which means that the transfer is blocking. Upon calling the function, the application blocks until transfer completion with or without an error. A timeout can be specified to avoid waiting forever. Listing - Serial Read and Write Example presents a read and write example to receive data from the host using the bulk OUT endpoint and to send data to the host using the bulk IN endpoint.

CPU_INT08U  rx_buf[2];
CPU_INT08U  tx_buf[2];
USBD_ERR    err;


(void)USBD_ACM_SerialRx(subclass_nbr,                                         (1)
                       &rx_buf[0],                                            (2)
                        2u,
                        0u,                                                   (3)
                       &err);
if (err != USBD_ERR_NONE) {
    /* Handle the error. */
}

(void)USBD_ACM_SerialTx(subclass_nbr,                                         (1)
                       &tx_buf[0],                                            (4)
                        2u,
                        0u,                                                   (3)
                       &err);
if (err != USBD_ERR_NONE) {
    /* Handle the error. */
}

(1) The class instance number created with USBD_ACM_SerialAdd() will serve internally to the ACM subclass to route the transfer to the proper bulk OUT or IN endpoint.

(2) The application must ensure that the buffer provided to the function is large enough to accommodate all the data. Otherwise, synchronization issues might happen.

(3) In order to avoid an infinite blocking situation, a timeout expressed in milliseconds can be specified. A value of ‘0’ makes the application task wait forever.

(4) The application provides the initialized transmit buffer.