Merge branch 'feature/usb/voltage_monitoring' into 'master'

tinyusb: Add voltage monitoring feature

Closes IDFGH-6065 and IDF-5229

See merge request espressif/esp-idf!20296
This commit is contained in:
Tomas Rezucha 2022-10-18 22:41:24 +08:00
commit 446daa9865
16 changed files with 217 additions and 91 deletions

View File

@ -18,7 +18,7 @@ set(srcs
"uart_periph.c"
"usb_periph.c"
"temperature_sensor_periph.c"
"usb_phy_periph.c")
"usb_otg_periph.c")
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}")

View File

@ -0,0 +1,34 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/usb_otg_periph.h"
#include "soc/gpio_sig_map.h"
/*
Bunch of constants for USB peripheral: GPIO signals
*/
const usb_phy_signal_conn_t usb_otg_periph_signal = {
.extphy_vp_in = USB_EXTPHY_VP_IDX,
.extphy_vm_in = USB_EXTPHY_VM_IDX,
.extphy_rcv_in = USB_EXTPHY_RCV_IDX,
.extphy_oen_out = USB_EXTPHY_OEN_IDX,
.extphy_vpo_out = USB_EXTPHY_VPO_IDX,
.extphy_vmo_out = USB_EXTPHY_VMO_IDX,
.extphy_suspend_in = USB_EXTPHY_SUSPND_IDX,
.extphy_speed_in = USB_EXTPHY_SPEED_IDX,
.srp_bvalid_in = USB_SRP_BVALID_IN_IDX,
.srp_sessend_in = USB_SRP_SESSEND_IN_IDX,
.srp_chrgvbus_out = USB_SRP_CHRGVBUS_IDX,
.srp_dischrgvbus_out = USB_SRP_DISCHRGVBUS_IDX,
.otg_iddig_in = USB_OTG_IDDIG_IN_IDX,
.otg_avalid_in = USB_OTG_AVALID_IN_IDX,
.otg_vbusvalid_in = USB_OTG_VBUSVALID_IN_IDX,
.otg_idpullup_out = USB_OTG_IDPULLUP_IDX,
.otg_dppulldown_out = USB_OTG_DPPULLDOWN_IDX,
.otg_dmpulldown_out = USB_OTG_DMPULLDOWN_IDX,
.otg_drvvbus_out = USB_OTG_DRVVBUS_IDX,
.module = PERIPH_USB_MODULE
};

View File

@ -1,23 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/usb_phy_periph.h"
#include "soc/gpio_sig_map.h"
/*
Bunch of constants for USB peripheral: GPIO signals
*/
const usb_phy_signal_conn_t usb_phy_periph_signal = {
.extphy_vp_in = USB_EXTPHY_VP_IDX,
.extphy_vm_in = USB_EXTPHY_VM_IDX,
.extphy_rcv_in = USB_EXTPHY_RCV_IDX,
.extphy_oen_out = USB_EXTPHY_OEN_IDX,
.extphy_vpo_out = USB_EXTPHY_VPO_IDX,
.extphy_vmo_out = USB_EXTPHY_VMO_IDX,
.extphy_suspend_in = USB_EXTPHY_SUSPND_IDX,
.extphy_speed_in = USB_EXTPHY_SPEED_IDX,
.module = PERIPH_USB_MODULE
};

View File

@ -21,7 +21,7 @@ set(srcs
"temperature_sensor_periph.c"
"uart_periph.c"
"usb_periph.c"
"usb_phy_periph.c")
"usb_otg_periph.c")
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}")

View File

@ -0,0 +1,34 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/usb_otg_periph.h"
#include "soc/gpio_sig_map.h"
/*
Bunch of constants for USB peripheral: GPIO signals
*/
const usb_phy_signal_conn_t usb_otg_periph_signal = {
.extphy_vp_in = USB_EXTPHY_VP_IDX,
.extphy_vm_in = USB_EXTPHY_VM_IDX,
.extphy_rcv_in = USB_EXTPHY_RCV_IDX,
.extphy_oen_out = USB_EXTPHY_OEN_IDX,
.extphy_vpo_out = USB_EXTPHY_VPO_IDX,
.extphy_vmo_out = USB_EXTPHY_VMO_IDX,
.extphy_suspend_in = USB_EXTPHY_SUSPND_IDX,
.extphy_speed_in = USB_EXTPHY_SPEED_IDX,
.srp_bvalid_in = USB_SRP_BVALID_IN_IDX,
.srp_sessend_in = USB_SRP_SESSEND_IN_IDX,
.srp_chrgvbus_out = USB_SRP_CHRGVBUS_IDX,
.srp_dischrgvbus_out = USB_SRP_DISCHRGVBUS_IDX,
.otg_iddig_in = USB_OTG_IDDIG_IN_IDX,
.otg_avalid_in = USB_OTG_AVALID_IN_IDX,
.otg_vbusvalid_in = USB_OTG_VBUSVALID_IN_IDX,
.otg_idpullup_out = USB_OTG_IDPULLUP_IDX,
.otg_dppulldown_out = USB_OTG_DPPULLDOWN_IDX,
.otg_dmpulldown_out = USB_OTG_DMPULLDOWN_IDX,
.otg_drvvbus_out = USB_OTG_DRVVBUS_IDX,
.module = PERIPH_USB_MODULE
};

View File

@ -1,23 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/usb_phy_periph.h"
#include "soc/gpio_sig_map.h"
/*
Bunch of constants for USB peripheral: GPIO signals
*/
const usb_phy_signal_conn_t usb_phy_periph_signal = {
.extphy_vp_in = USB_EXTPHY_VP_IDX,
.extphy_vm_in = USB_EXTPHY_VM_IDX,
.extphy_rcv_in = USB_EXTPHY_RCV_IDX,
.extphy_oen_out = USB_EXTPHY_OEN_IDX,
.extphy_vpo_out = USB_EXTPHY_VPO_IDX,
.extphy_vmo_out = USB_EXTPHY_VMO_IDX,
.extphy_suspend_in = USB_EXTPHY_SUSPND_IDX,
.extphy_speed_in = USB_EXTPHY_SPEED_IDX,
.module = PERIPH_USB_MODULE
};

View File

@ -25,10 +25,21 @@ typedef struct {
const uint8_t extphy_vmo_out;
const uint8_t extphy_suspend_in;
const uint8_t extphy_speed_in;
const uint8_t srp_bvalid_in;
const uint8_t srp_sessend_in;
const uint8_t srp_chrgvbus_out;
const uint8_t srp_dischrgvbus_out;
const uint8_t otg_iddig_in;
const uint8_t otg_avalid_in;
const uint8_t otg_vbusvalid_in;
const uint8_t otg_idpullup_out;
const uint8_t otg_dppulldown_out;
const uint8_t otg_dmpulldown_out;
const uint8_t otg_drvvbus_out;
const periph_module_t module;
} usb_phy_signal_conn_t;
extern const usb_phy_signal_conn_t usb_phy_periph_signal;
extern const usb_phy_signal_conn_t usb_otg_periph_signal;
#ifdef __cplusplus
}

View File

@ -19,7 +19,12 @@ extern "C" {
#endif
/**
* @brief Configuration structure of the tinyUSB core
* @brief Configuration structure of the TinyUSB core
*
* USB specification mandates self-powered devices to monitor USB VBUS to detect connection/disconnection events.
* If you want to use this feature, connected VBUS to any free GPIO through a voltage divider or voltage comparator.
* The voltage divider output should be (0.75 * Vdd) if VBUS is 4.4V (lowest valid voltage at device port).
* The comparator thresholds should be set with hysteresis: 4.35V (falling edge) and 4.75V (raising edge).
*/
typedef struct {
union {
@ -29,6 +34,8 @@ typedef struct {
const char **string_descriptor; /*!< Pointer to an array of string descriptors */
bool external_phy; /*!< Should USB use an external PHY */
const uint8_t *configuration_descriptor; /*!< Pointer to a configuration descriptor. If set to NULL, TinyUSB device will use a default configuration descriptor whose values are set in Kconfig */
bool self_powered; /*!< This is a self-powered USB device. USB VBUS must be monitored. */
int vbus_monitor_io; /*!< GPIO for VBUS monitoring. Ignored if not self_powered. */
} tinyusb_config_t;
/**

View File

@ -32,7 +32,9 @@ esp_err_t tinyusb_driver_install(const tinyusb_config_t *config)
.controller = USB_PHY_CTRL_OTG,
.otg_mode = USB_OTG_MODE_DEVICE,
};
usb_phy_gpio_conf_t gpio_conf = {
// External PHY IOs config
usb_phy_ext_io_conf_t ext_io_conf = {
.vp_io_num = USBPHY_VP_NUM,
.vm_io_num = USBPHY_VM_NUM,
.rcv_io_num = USBPHY_RCV_NUM,
@ -42,10 +44,16 @@ esp_err_t tinyusb_driver_install(const tinyusb_config_t *config)
};
if (config->external_phy) {
phy_conf.target = USB_PHY_TARGET_EXT;
phy_conf.gpio_conf = &gpio_conf;
phy_conf.ext_io_conf = &ext_io_conf;
} else {
phy_conf.target = USB_PHY_TARGET_INT;
}
// OTG IOs config
const usb_phy_otg_io_conf_t otg_io_conf = USB_PHY_SELF_POWERED_DEVICE(config->vbus_monitor_io);
if (config->self_powered) {
phy_conf.otg_io_conf = &otg_io_conf;
}
ESP_RETURN_ON_ERROR(usb_new_phy(&phy_conf, &phy_hdl), TAG, "Install USB PHY failed");
#if (CONFIG_TINYUSB_HID_COUNT > 0)

View File

@ -15,6 +15,24 @@
extern "C" {
#endif
/**
* @brief Initialization for usb_phy_otg_io_conf_t: Self-powered device
*/
#define USB_PHY_SELF_POWERED_DEVICE(vbus_monitor_io) \
{ \
.iddig_io_num = -1, \
.avalid_io_num = -1, \
.vbusvalid_io_num = -1, \
.idpullup_io_num = -1, \
.dppulldown_io_num = -1, \
.dmpulldown_io_num = -1, \
.drvvbus_io_num = -1, \
.bvalid_io_num = vbus_monitor_io, \
.sessend_io_num = -1, \
.chrgvbus_io_num = -1, \
.dischrgvbus_io_num = -1, \
};
/**
* @brief USB PHY status
*/
@ -33,7 +51,7 @@ typedef enum {
} usb_phy_action_t;
/**
* @brief USB external PHY iopins configure struct
* @brief USB external PHY IO pins configuration structure
*/
typedef struct {
int vp_io_num; /**< GPIO pin to USB_EXTPHY_VP_IDX */
@ -42,7 +60,24 @@ typedef struct {
int oen_io_num; /**< GPIO pin to USB_EXTPHY_OEN_IDX */
int vpo_io_num; /**< GPIO pin to USB_EXTPHY_VPO_IDX */
int vmo_io_num; /**< GPIO pin to USB_EXTPHY_VMO_IDX */
} usb_phy_gpio_conf_t;
} usb_phy_ext_io_conf_t;
/**
* @brief USB OTG IO pins configuration structure
*/
typedef struct {
int iddig_io_num; /**< GPIO pin to USB_OTG_IDDIG_IN_IDX */
int avalid_io_num; /**< GPIO pin to USB_OTG_AVALID_IN_IDX */
int vbusvalid_io_num; /**< GPIO pin to USB_OTG_VBUSVALID_IN_IDX */
int idpullup_io_num; /**< GPIO pin to USB_OTG_IDPULLUP_IDX */
int dppulldown_io_num; /**< GPIO pin to USB_OTG_DPPULLDOWN_IDX */
int dmpulldown_io_num; /**< GPIO pin to USB_OTG_DMPULLDOWN_IDX */
int drvvbus_io_num; /**< GPIO pin to USB_OTG_DRVVBUS_IDX */
int bvalid_io_num; /**< GPIO pin to USB_SRP_BVALID_IN_IDX */
int sessend_io_num; /**< GPIO pin to USB_SRP_SESSEND_IN_IDX */
int chrgvbus_io_num; /**< GPIO pin to USB_SRP_CHRGVBUS_IDX */
int dischrgvbus_io_num; /**< GPIO pin to USB_SRP_DISCHRGVBUS_IDX */
} usb_phy_otg_io_conf_t;
/**
* @brief USB PHY configure struct
@ -50,11 +85,12 @@ typedef struct {
* At minimum the PHY controller and PHY target must be initialized.
*/
typedef struct {
usb_phy_controller_t controller; /**< USB PHY controller */
usb_phy_target_t target; /**< USB PHY target INT/EXT */
usb_otg_mode_t otg_mode; /**< USB OTG mode */
usb_phy_speed_t otg_speed; /**< USB OTG speed */
usb_phy_gpio_conf_t *gpio_conf; /**< USB external PHY iopins configure */
usb_phy_controller_t controller; /**< USB PHY controller */
usb_phy_target_t target; /**< USB PHY target INT/EXT */
usb_otg_mode_t otg_mode; /**< USB OTG mode */
usb_phy_speed_t otg_speed; /**< USB OTG speed */
const usb_phy_ext_io_conf_t *ext_io_conf; /**< USB external PHY IO pins configuration */
const usb_phy_otg_io_conf_t *otg_io_conf; /**< USB OTG IO pins configuration */
} usb_phy_config_t;
typedef struct phy_context_t *usb_phy_handle_t; /**< USB PHY context handle */

View File

@ -22,7 +22,8 @@ void test_usb_init_phy(void)
.target = USB_PHY_TARGET_INT,
.otg_mode = USB_OTG_MODE_HOST,
.otg_speed = USB_PHY_SPEED_UNDEFINED, //In Host mode, the speed is determined by the connected device
.gpio_conf = NULL,
.ext_io_conf = NULL,
.otg_io_conf = NULL,
};
ESP_ERROR_CHECK(usb_new_phy(&phy_config, &phy_hdl));
}

View File

@ -384,7 +384,8 @@ esp_err_t usb_host_install(const usb_host_config_t *config)
.target = USB_PHY_TARGET_INT,
.otg_mode = USB_OTG_MODE_HOST,
.otg_speed = USB_PHY_SPEED_UNDEFINED, //In Host mode, the speed is determined by the connected device
.gpio_conf = NULL,
.ext_io_conf = NULL,
.otg_io_conf = NULL,
};
ret = usb_new_phy(&phy_config, &host_lib_obj->constant.phy_handle);
if (ret != ESP_OK) {

View File

@ -11,7 +11,7 @@
#include "esp_check.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/usb_phy.h"
#include "soc/usb_phy_periph.h"
#include "soc/usb_otg_periph.h"
#include "hal/usb_phy_hal.h"
#include "hal/usb_phy_ll.h"
#include "esp_rom_gpio.h"
@ -31,7 +31,7 @@ struct phy_context_t {
usb_phy_status_t status; /**< PHY status */
usb_otg_mode_t otg_mode; /**< USB OTG mode */
usb_phy_speed_t otg_speed; /**< USB speed */
usb_phy_gpio_conf_t *iopins; /**< external PHY I/O pins */
usb_phy_ext_io_conf_t *iopins; /**< external PHY I/O pins */
usb_phy_hal_context_t hal_context; /**< USB_PHY hal context */
};
@ -53,20 +53,11 @@ typedef struct {
static phy_ctrl_obj_t *p_phy_ctrl_obj = NULL;
static portMUX_TYPE phy_spinlock = portMUX_INITIALIZER_UNLOCKED;
static esp_err_t phy_external_iopins_configure(usb_phy_gpio_conf_t *gpio_conf)
static esp_err_t phy_iopins_configure(const usb_iopin_dsc_t *usb_periph_iopins, int iopins_num)
{
const usb_iopin_dsc_t usb_periph_iopins[] = {
{gpio_conf->vp_io_num, usb_phy_periph_signal.extphy_vp_in, 0},
{gpio_conf->vm_io_num, usb_phy_periph_signal.extphy_vm_in, 0},
{gpio_conf->rcv_io_num, usb_phy_periph_signal.extphy_rcv_in, 0},
{gpio_conf->oen_io_num, usb_phy_periph_signal.extphy_oen_out, 1},
{gpio_conf->vpo_io_num, usb_phy_periph_signal.extphy_vpo_out, 1},
{gpio_conf->vmo_io_num, usb_phy_periph_signal.extphy_vmo_out, 1},
};
for (int i = 0; i < sizeof(usb_periph_iopins)/sizeof(usb_iopin_dsc_t); i++) {
for (int i = 0; i < iopins_num; i++) {
const usb_iopin_dsc_t iopin = usb_periph_iopins[i];
if (iopin.pin != -1) {
if (iopin.pin != GPIO_NUM_NC) {
ESP_RETURN_ON_FALSE((iopin.is_output && GPIO_IS_VALID_OUTPUT_GPIO(iopin.pin)) ||
(!iopin.is_output && GPIO_IS_VALID_GPIO(iopin.pin)),
ESP_ERR_INVALID_ARG, USBPHY_TAG, "io_num argument is invalid");
@ -83,6 +74,38 @@ static esp_err_t phy_external_iopins_configure(usb_phy_gpio_conf_t *gpio_conf)
return ESP_OK;
}
static esp_err_t phy_external_iopins_configure(const usb_phy_ext_io_conf_t *ext_io_conf)
{
const usb_iopin_dsc_t usb_periph_iopins[] = {
{ext_io_conf->vp_io_num, usb_otg_periph_signal.extphy_vp_in, false},
{ext_io_conf->vm_io_num, usb_otg_periph_signal.extphy_vm_in, false},
{ext_io_conf->rcv_io_num, usb_otg_periph_signal.extphy_rcv_in, false},
{ext_io_conf->oen_io_num, usb_otg_periph_signal.extphy_oen_out, true},
{ext_io_conf->vpo_io_num, usb_otg_periph_signal.extphy_vpo_out, true},
{ext_io_conf->vmo_io_num, usb_otg_periph_signal.extphy_vmo_out, true},
};
return phy_iopins_configure(usb_periph_iopins, sizeof(usb_periph_iopins)/sizeof(usb_iopin_dsc_t));
}
static esp_err_t phy_otg_iopins_configure(const usb_phy_otg_io_conf_t *otg_io_conf)
{
const usb_iopin_dsc_t usb_periph_iopins[] = {
{otg_io_conf->iddig_io_num, usb_otg_periph_signal.otg_iddig_in, false},
{otg_io_conf->avalid_io_num, usb_otg_periph_signal.otg_avalid_in, false},
{otg_io_conf->vbusvalid_io_num, usb_otg_periph_signal.otg_vbusvalid_in, false},
{otg_io_conf->idpullup_io_num, usb_otg_periph_signal.otg_idpullup_out, true},
{otg_io_conf->dppulldown_io_num, usb_otg_periph_signal.otg_dppulldown_out, true},
{otg_io_conf->dmpulldown_io_num, usb_otg_periph_signal.otg_dmpulldown_out, true},
{otg_io_conf->drvvbus_io_num, usb_otg_periph_signal.otg_drvvbus_out, true},
{otg_io_conf->bvalid_io_num, usb_otg_periph_signal.srp_bvalid_in, false},
{otg_io_conf->sessend_io_num, usb_otg_periph_signal.srp_sessend_in, false},
{otg_io_conf->chrgvbus_io_num, usb_otg_periph_signal.srp_chrgvbus_out, true},
{otg_io_conf->dischrgvbus_io_num, usb_otg_periph_signal.srp_dischrgvbus_out, true},
};
return phy_iopins_configure(usb_periph_iopins, sizeof(usb_periph_iopins)/sizeof(usb_iopin_dsc_t));
}
esp_err_t usb_phy_otg_set_mode(usb_phy_handle_t handle, usb_otg_mode_t mode)
{
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, USBPHY_TAG, "handle argument is invalid");
@ -197,8 +220,8 @@ static esp_err_t usb_phy_install(void)
goto cleanup;
}
portEXIT_CRITICAL(&phy_spinlock);
periph_module_enable(usb_phy_periph_signal.module);
periph_module_reset(usb_phy_periph_signal.module);
periph_module_enable(usb_otg_periph_signal.module);
periph_module_reset(usb_otg_periph_signal.module);
return ESP_OK;
cleanup:
@ -254,10 +277,10 @@ esp_err_t usb_new_phy(const usb_phy_config_t *config, usb_phy_handle_t *handle_r
}
*handle_ret = (usb_phy_handle_t) phy_context;
if (config->gpio_conf && config->target == USB_PHY_TARGET_EXT) {
phy_context->iopins = (usb_phy_gpio_conf_t *) calloc(1, sizeof(usb_phy_gpio_conf_t));
if (config->ext_io_conf && config->target == USB_PHY_TARGET_EXT) {
phy_context->iopins = (usb_phy_ext_io_conf_t *) calloc(1, sizeof(usb_phy_ext_io_conf_t));
ESP_GOTO_ON_FALSE(phy_context->iopins, ESP_ERR_NO_MEM, cleanup, USBPHY_TAG, "no mem for storing I/O pins");
memcpy(phy_context->iopins, config->gpio_conf, sizeof(usb_phy_gpio_conf_t));
memcpy(phy_context->iopins, config->ext_io_conf, sizeof(usb_phy_ext_io_conf_t));
ESP_ERROR_CHECK(phy_external_iopins_configure(phy_context->iopins));
}
if (config->otg_mode != USB_PHY_MODE_DEFAULT) {
@ -266,6 +289,9 @@ esp_err_t usb_new_phy(const usb_phy_config_t *config, usb_phy_handle_t *handle_r
if (config->otg_speed != USB_PHY_SPEED_UNDEFINED) {
ESP_ERROR_CHECK(usb_phy_otg_dev_set_speed(*handle_ret, config->otg_speed));
}
if (config->otg_io_conf && (phy_context->controller == USB_PHY_CTRL_OTG)) {
ESP_ERROR_CHECK(phy_otg_iopins_configure(config->otg_io_conf));
}
return ESP_OK;
cleanup:
@ -286,7 +312,7 @@ static void phy_uninstall(void)
p_phy_ctrl_obj_free = p_phy_ctrl_obj;
p_phy_ctrl_obj = NULL;
// Disable USB peripheral
periph_module_disable(usb_phy_periph_signal.module);
periph_module_disable(usb_otg_periph_signal.module);
}
portEXIT_CRITICAL(&phy_spinlock);
free(p_phy_ctrl_obj_free);

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 92 KiB

View File

@ -13,7 +13,7 @@ Overview
The driver allows you to use {IDF_TARGET_NAME} chips to develop USB devices on a top of TinyUSB stack. TinyUSB is integrated with ESP-IDF to provide USB features of the framework. Using this driver the chip works as simple or composite device supporting several USB devices simultaneously.
Our USB-OTG implementation is limited to {IDF_TARGET_USB_EP_NUM} number of USB endpoints ({IDF_TARGET_USB_EP_NUM_INOUT} IN/OUT endpoints and {IDF_TARGET_USB_EP_NUM_IN} IN endpoint) - find more information in `technical reference manual <{IDF_TARGET_TRM_EN_URL}>`_.
Our USB-OTG implementation is limited to {IDF_TARGET_USB_EP_NUM} USB endpoints ({IDF_TARGET_USB_EP_NUM_INOUT} IN/OUT endpoints and {IDF_TARGET_USB_EP_NUM_IN} IN endpoint) - find more information in `technical reference manual <{IDF_TARGET_TRM_EN_URL}>`_.
Features
--------
@ -22,7 +22,7 @@ Features
- USB Serial Device (CDC-ACM)
- Input and output streams through USB Serial Device
- Other USB classes (MIDI, MSC, HID...) support directly via TinyUSB
- VBUS monitoring for self-powered devices
Hardware USB Connection
-----------------------
@ -36,9 +36,11 @@ On {IDF_TARGET_NAME}, connect GPIO {IDF_TARGET_USB_DP_GPIO_NUM} and {IDF_TARGET_
.. figure:: ../../../_static/usb-board-connection.png
:align: center
:alt: Connection of a board to a host ESP chip
:alt: Connection of an ESP board to a USB host
:figclass: align-center
Self-powered devices must also connect VBUS through voltage divider or comparator, more details in :ref:`self-powered-device` subchapter.
Driver Structure
----------------
@ -51,8 +53,6 @@ On top of it the driver implements:
- Redirecting of standard streams through the Serial device
- Encapsulated driver's task servicing the TinyUSB
Configuration
-------------
@ -63,7 +63,6 @@ Via Menuconfig options you can specify:
- The verbosity of the TinyUSB's log
- Disable the TinyUSB main task (for the custom implementation)
Descriptors Configuration
^^^^^^^^^^^^^^^^^^^^^^^^^
@ -81,9 +80,9 @@ However, the driver also provides default descriptors. You can install the drive
If you want to use your own descriptors with extended modification, you can define them during the driver installation process.
Install Driver
--------------
To initialize the driver, users should call :cpp:func:`tinyusb_driver_install`. The driver's configuration is specified in a :cpp:type:`tinyusb_config_t` structure that is passed as an argument to :cpp:func:`tinyusb_driver_install`.
Note that the :cpp:type:`tinyusb_config_t` structure can be zero initialized (e.g. ``const tinyusb_config_t tusb_cfg = { 0 };``) or partially (as shown below). For any member that is initialized to `0` or `NULL`, the driver will use its default configuration values for that member (see example below)
@ -97,6 +96,24 @@ To initialize the driver, users should call :cpp:func:`tinyusb_driver_install`.
.configuration_descriptor = NULL, // Use default configuration descriptor according to settings in Menuconfig
};
.. _self-powered-device:
Self-Powered Device
-------------------
USB specification mandates self-powered devices to monitor voltage level on USB's VBUS signal. As opposed to bus-powered devices, a self-powered device can be fully functional even without USB connection. The self-powered device detects connection and disconnection events by monitoring the VBUS voltage level. VBUS is considered valid if it rises above 4.75V and invalid if it falls below 4.35V.
No {IDF_TARGET_NAME} pin is 5V tolerant, so you must connect the VBUS to {IDF_TARGET_NAME} via a comparator with voltage thresholds as described above, or use a simple resistor voltage divider that will output (0.75 x Vdd) if VBUS is 4.4V (see figure below). In both cases, voltage on the sensing pin must be logic low within 3ms after the device is unplugged from USB host.
.. figure:: ../../../_static/diagrams/usb/usb_vbus_voltage_monitor.png
:align: center
:alt: Simple voltage divider for VBUS monitoring
:figclass: align-center
Simple voltage divider for VBUS monitoring
To use this feature, in :cpp:type:`tinyusb_config_t` you must set :cpp:member:`self_powered` to ``true`` and :cpp:member:`vbus_monitor_io` to GPIO number that will be used for VBUS monitoring.
USB Serial Device (CDC-ACM)
---------------------------
@ -122,7 +139,6 @@ USB Serial Console
The driver allows to redirect all standard application streams (stdinm stdout, stderr) to the USB Serial Device and return them to UART using :cpp:func:`esp_tusb_init_console`/:cpp:func:`esp_tusb_deinit_console` functions.
Application Examples
--------------------
@ -143,7 +159,6 @@ The table below describes the code examples available in the directory :example:
* - :example:`peripherals/usb/device/tusb_hid`
- How to set up {IDF_TARGET_NAME} chip to work as a USB Human Interface Device
API Reference
-------------
@ -153,4 +168,3 @@ API Reference
.. include-build-file:: inc/tusb_console.inc
.. include-build-file:: inc/tusb_tasks.inc
.. include-build-file:: inc/vfs_tinyusb.inc