USB Component  Version 6.17.0
MDK Middleware for USB Device and Host Communication

Initialize and manage the USB Device Core statically and at run-time. More...

Content

 User API
 User API reference of the USB Device Core.
 
 Configuration
 Configuration of the USB Device Core.
 

Description

Initialize and manage the USB Device Core statically and at run-time.

The Core of the USB Device has standard functions that are used to initialize and start the USB Device. These functions must be used before any class specific functions are called:

These two functions are accompanied USBD_Disconnect and USBD_Uninitialize. Use them to properly disconnect and uninitialize the device from the USB bus.

Static and Run-Time Configuration

The USB Device Core is statically configured using the USBD_Config_n.c file. However, for mass-production it is often required to be able to configure some USB Device settings at run-time (for example the serial number which needs to be unique for every single device). To achieve this, the following device configuration functions are part of the USBD_User_Device_n.c user code template. They enable user specific USB Control Endpoint 0 request handling. This allows the user to intercept all Control Endpoint 0 requests and handle them overriding the default USB Library handling:

Setup Packets on Control Endpoint 0

Setup packets sent to Control Endpoint 0 are received by the USB Device Core. The USB Device Core will call the USBD_Devicen_Endpoint0_SetupPacketReceived function and pass the setup packet to it. Depending on the return code of USBD_Devicen_Endpoint0_SetupPacketReceived, the USB Device Core either passes the processing to the Custom Class function if custom class is used and if message is addressed to a custom class by calling USBD_CustomClassn_Endpoint0_SetupPacketReceived function or continues to process the received setup packet itself. Depending on the return code of USBD_CustomClassn_Endpoint0_SetupPacketReceived, processing of the setup packet is either done or continues to be processed by USB Device Core.

USB Device Core will call USBD_Devicen_Endpoint0_SetupPacketProcessed and depending on return code it will call USBD_CustomClassn_Endpoint0_SetupPacketProcessed to inform the application that setup packet has been processed by USB Device Core.

If custom handling of request was used and request contains data stage, USB Device Core will call USBD_Devicen_Endpoint0_OutDataReceived and depending on return code it will call USBD_CustomClassn_Endpoint0_OutDataReceived after data expected by request was received, it will call USBD_Devicen_Endpoint0_InDataSent and depending on return code it will call USBD_CustomClassn_Endpoint0_InDataSent after data expected by request was sent.

msc_inline_mscgraph_1

Implementation

To create a USB Device:

User Code Templates
There are two user code templates available that help to configure the USB Device at run-time:

  1. USBD_User_Device_n.c contains all the callback functions that need to be implemented by the user.
  2. USBD_User_Device_SerNum_n.c is a code template that creates a custom serial number for a USB Device. This serial number will override the one that is set in the USBD_Config_n.c file.

User Code Template USBD_User_Device_n.c

The following source code can be used to implement the application specific behavior of a USB Device.

/*------------------------------------------------------------------------------
* MDK Middleware - Component ::USB:Device
* Copyright (c) 2004-2020 Arm Limited (or its affiliates). All rights reserved.
*------------------------------------------------------------------------------
* Name: USBD_User_Device_n.c
* Purpose: USB Device User module
* Rev.: V6.8.2
*----------------------------------------------------------------------------*/
/*
* USBD_User_Device_n.c is a code template for the user specific
* Device events and Control Endpoint 0 requests handling. It allows user to
* handle all user level events as well as to intercept all Control Endpoint 0
* requests and handle them overriding the default USB Library handling.
*
* Uncomment "Example code" lines to override USB Device Descriptor.
*
* IMPORTANT NOTE!!!: Maximum packet size must not be set to less that 32 bytes!
*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "rl_usb.h"
//static const uint8_t devicen_dev_desc[] = {
// 18, /* bLength = 18 bytes */
// USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType = Device Desc */
// 0x00, 0x02, /* bcdUSB = 2.00 */
// 0x00, /* bDeviceClass = Defined in IF */
// 0x00, /* bDeviceSubClass = Defined in IF */
// 0x00, /* bDeviceProtocol = Defined in IF */
// 64, /* bMaxPacketSize0 = 64 bytes !!! Must be same as USBDn_MAX_PACKET0 in USBD_Config_n.c */
// 0x51, 0xC2, /* idVendor = 0xC251 */
// 0x01, 0x00, /* idProduct = 1 */
// 0x00, 0x01, /* bcdDevice = 1.00 */
// 0x01, /* iManufacturer = String1 */
// 0x02, /* iProduct = String2 */
// 0x03, /* iSerialNumber = String3 */
// 0x01 /* bNumConfigurations = 1 config */
//};
//static bool handle_request;
// \brief Callback function called during USBD_Initialize to initialize the USB Device
// Handle Device Initialization
// handle_request = false;
}
// \brief Callback function called during USBD_Uninitialize to de-initialize the USB Device
// Handle Device De-initialization
}
// \brief Callback function called when VBUS level changes
// \param[in] level current VBUS level
// - true: VBUS level is high
// - false: VBUS level is low
void USBD_Devicen_VbusChanged (bool level) {
(void)level;
}
// \brief Callback function called upon USB Bus Reset signaling
void USBD_Devicen_Reset (void) {
}
// \brief Callback function called when USB Bus speed was changed to high-speed
}
// \brief Callback function called when USB Bus goes into suspend mode (no bus activity for 3 ms)
}
// \brief Callback function called when USB Bus activity resumes
void USBD_Devicen_Resumed (void) {
}
// \brief Callback function called when Device was successfully enumerated
// \param[in] val current configuration value
// - value 0: not configured
// - value > 0: active configuration
(void)val;
}
// \brief Callback function called when Set Feature for Remote Wakeup comes over Control Endpoint 0
}
// \brief Callback function called when Clear Feature for Remote Wakeup comes over Control Endpoint 0
}
// \brief Callback function called when Device n received SETUP PACKET on Control Endpoint 0
// \param[in] setup_packet pointer to received setup packet.
// \param[out] buf pointer to data buffer used for data stage requested by setup packet.
// \param[out] len pointer to number of data bytes in data stage requested by setup packet.
// \return usbdRequestStatus enumerator value indicating the function execution status
// \return usbdRequestNotProcessed: request was not processed; processing will be done by USB library
// \return usbdRequestOK: request was processed successfully (send Zero-Length Packet if no data stage)
// \return usbdRequestStall: request was processed but is not supported (stall Endpoint 0)
usbdRequestStatus USBD_Devicen_Endpoint0_SetupPacketReceived (const USB_SETUP_PACKET *setup_packet, uint8_t **buf, uint32_t *len) {
(void)buf;
(void)len;
switch (setup_packet->bmRequestType.Type) {
case USB_REQUEST_STANDARD:
// // Example code handling Get Device Descriptor request:
// if ((setup_packet->bmRequestType.Dir == USB_REQUEST_DEVICE_TO_HOST) && // Request to get
// (setup_packet->bmRequestType.Recipient == USB_REQUEST_TO_DEVICE ) && // from device
// (setup_packet->bRequest == USB_REQUEST_GET_DESCRIPTOR) && // the descriptor
// ((setup_packet->wValue >> 8) == USB_DEVICE_DESCRIPTOR_TYPE) && // Device Descriptor Type
// (setup_packet->wIndex == 0U )) { // Index = 0
// *buf = (uint8_t *)((uint32_t)devicen_dev_desc);
// *len = sizeof (devicen_dev_desc);
// handle_request = true;
// return usbdRequestOK;
// }
break;
case USB_REQUEST_CLASS:
break;
case USB_REQUEST_VENDOR:
break;
case USB_REQUEST_RESERVED:
break;
default:
break;
}
}
// \brief Callback function called when SETUP PACKET was processed by USB library
// \param[in] setup_packet pointer to processed setup packet.
switch (setup_packet->bmRequestType.Type) {
case USB_REQUEST_STANDARD:
break;
case USB_REQUEST_CLASS:
break;
case USB_REQUEST_VENDOR:
break;
case USB_REQUEST_RESERVED:
break;
default:
break;
}
}
// \brief Callback function called when Device n received OUT DATA on Control Endpoint 0
// \param[in] len number of received data bytes.
// \return usbdRequestStatus enumerator value indicating the function execution status
// \return usbdRequestNotProcessed: request was not processed; processing will be done by USB library
// \return usbdRequestOK: request was processed successfully (send Zero-Length Packet)
// \return usbdRequestStall: request was processed but is not supported (stall Endpoint 0)
// \return usbdRequestNAK: request was processed but the device is busy (return NAK)
usbdRequestStatus USBD_Devicen_Endpoint0_OutDataReceived (uint32_t len) {
(void)len;
}
// \brief Callback function called when Device n sent IN DATA on Control Endpoint 0
// \param[in] len number of sent data bytes.
// \return usbdRequestStatus enumerator value indicating the function execution status
// \return usbdRequestNotProcessed: request was not processed; processing will be done by USB library
// \return usbdRequestOK: request was processed successfully (return ACK)
// \return usbdRequestStall: request was processed but is not supported (stall Endpoint 0)
// \return usbdRequestNAK: request was processed but the device is busy (return NAK)
usbdRequestStatus USBD_Devicen_Endpoint0_InDataSent (uint32_t len) {
(void)len;
// // Example code after Get Device Descriptor was sent:
// if (handle_request) { // If Device Descriptor was sent
// handle_request = false;
// return usbdRequestOK; // Acknowledge custom handled request
// }
}

User Code Template USBD_User_Device_SerNum_n.c

The following source code can be used to set an application specific serial number for the USB Device.

/*------------------------------------------------------------------------------
* MDK Middleware - Component ::USB:Device
* Copyright (c) 2004-2023 Arm Limited (or its affiliates). All rights reserved.
*------------------------------------------------------------------------------
* Name: USBD_User_Device_SerNum_n.c
* Purpose: USB Device User module
* Rev.: V1.2.0
*----------------------------------------------------------------------------*/
/*
* USBD_User_Device_SerNum_n.c is a code template for the user specific
* Device events and Control Endpoint 0 requests handling. It demonstrates how
* to specify serial number at runtime instead of fixed one specified in
* USBD_Config_n.c file.
*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "rl_usb.h"
static bool handle_request;
static uint8_t ser_no_string_desc[32]; // String Descriptor runtime value
// \brief Callback function called during USBD_Initialize to initialize the USB Device
// Handle Device Initialization
handle_request = false;
}
// \brief Callback function called during USBD_Uninitialize to de-initialize the USB Device
// Handle Device De-initialization
}
// \brief Callback function called when VBUS level changes
// \param[in] level current VBUS level
// - true: VBUS level is high
// - false: VBUS level is low
void USBD_Devicen_VbusChanged (bool level) {
(void)level;
}
// \brief Callback function called upon USB Bus Reset signaling
void USBD_Devicen_Reset (void) {
}
// \brief Callback function called when USB Bus speed was changed to high-speed
}
// \brief Callback function called when USB Bus goes into suspend mode (no bus activity for 3 ms)
}
// \brief Callback function called when USB Bus activity resumes
void USBD_Devicen_Resumed (void) {
}
// \brief Callback function called when Device was successfully enumerated
// \param[in] val current configuration value
// - value 0: not configured
// - value > 0: active configuration
(void)val;
}
// \brief Callback function called when Set Feature for Remote Wakeup comes over Control Endpoint 0
}
// \brief Callback function called when Clear Feature for Remote Wakeup comes over Control Endpoint 0
}
// \brief Callback function called when Device n received SETUP PACKET on Control Endpoint 0
// \param[in] setup_packet pointer to received setup packet.
// \param[out] buf pointer to data buffer used for data stage requested by setup packet.
// \param[out] len pointer to number of data bytes in data stage requested by setup packet.
// \return usbdRequestStatus enumerator value indicating the function execution status
// \return usbdRequestNotProcessed: request was not processed; processing will be done by USB library
// \return usbdRequestOK: request was processed successfully (send Zero-Length Packet if no data stage)
// \return usbdRequestStall: request was processed but is not supported (stall Endpoint 0)
usbdRequestStatus USBD_Devicen_Endpoint0_SetupPacketReceived (const USB_SETUP_PACKET *setup_packet, uint8_t **buf, uint32_t *len) {
switch (setup_packet->bmRequestType.Type) {
case USB_REQUEST_STANDARD:
// Catch Get String Descriptor request for serial number string and return desired string:
if ((setup_packet->bmRequestType.Dir == USB_REQUEST_DEVICE_TO_HOST) && // Request to get
(setup_packet->bmRequestType.Recipient == USB_REQUEST_TO_DEVICE ) && // from device
(setup_packet->bRequest == USB_REQUEST_GET_DESCRIPTOR) && // the descriptor
((setup_packet->wValue >> 8) == USB_STRING_DESCRIPTOR_TYPE) && // String Descriptor Type
((setup_packet->wValue & 0xFFU) == 0x03U ) && // Index of String = 3
(setup_packet->wIndex == 0x0409U )) { // Language ID = 0x0409 = English (United States)
ser_no_string_desc[0] = 26U; // Total size of String Descriptor
ser_no_string_desc[1] = USB_STRING_DESCRIPTOR_TYPE; // String Descriptor Type
memcpy(&ser_no_string_desc[2], u"0001A0000001", 24); // Serial Number String value
*buf = ser_no_string_desc; // Return pointer to prepared String Descriptor
if (setup_packet->wLength >= 26) {
*len = 26U; // Number of bytes of whole String Descriptor
} else {
*len = setup_packet->wLength; // Requested number of bytes of String Descriptor
}
handle_request = true; // This request is handled
return usbdRequestOK; // Return status that custom handling for this request is used
}
break;
case USB_REQUEST_CLASS:
break;
case USB_REQUEST_VENDOR:
break;
case USB_REQUEST_RESERVED:
break;
default:
break;
}
}
// \brief Callback function called when SETUP PACKET was processed by USB library
// \param[in] setup_packet pointer to processed setup packet.
switch (setup_packet->bmRequestType.Type) {
case USB_REQUEST_STANDARD:
break;
case USB_REQUEST_CLASS:
break;
case USB_REQUEST_VENDOR:
break;
case USB_REQUEST_RESERVED:
break;
default:
break;
}
}
// \brief Callback function called when Device n received OUT DATA on Control Endpoint 0
// \param[in] len number of received data bytes.
// \return usbdRequestStatus enumerator value indicating the function execution status
// \return usbdRequestNotProcessed: request was not processed; processing will be done by USB library
// \return usbdRequestOK: request was processed successfully (send Zero-Length Packet)
// \return usbdRequestStall: request was processed but is not supported (stall Endpoint 0)
// \return usbdRequestNAK: request was processed but the device is busy (return NAK)
usbdRequestStatus USBD_Devicen_Endpoint0_OutDataReceived (uint32_t len) {
(void)len;
}
// \brief Callback function called when Device n sent IN DATA on Control Endpoint 0
// \param[in] len number of sent data bytes.
// \return usbdRequestStatus enumerator value indicating the function execution status
// \return usbdRequestNotProcessed: request was not processed; processing will be done by USB library
// \return usbdRequestOK: request was processed successfully (return ACK)
// \return usbdRequestStall: request was processed but is not supported (stall Endpoint 0)
// \return usbdRequestNAK: request was processed but the device is busy (return NAK)
usbdRequestStatus USBD_Devicen_Endpoint0_InDataSent (uint32_t len) {
(void)len;
if (handle_request) { // If String Descriptor was sent
handle_request = false;
return usbdRequestOK; // Acknowledge custom handled request
}
}