1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-18 12:52:44 +01:00
19471: drivers/periph_usbdev: fix set device address r=bergzand a=gschorcht

### Contribution description

This PR allows to define when the device address is set on receipt of a SETUP with `SET ADDRESS Request`. It fixes the problem with enumeration of the Synopsys DWC2 USB OTG Core due to the wrong time of setting the device address.

Especially, it fixes the problem that the enumeration fails completely for the `stm32f723e-disco` board with CDC ECM if CDC ACM is not used and the additional reset cycles during the enumeration for a couple of platforms such as ESP32-S2 and ESP32-S3.

**Background**

The address in the USB device can be set either directly after the SETUP stage on receipt of the `SET ADDRESS Request` or after the associated STATUS stage. When the USB device address has to be set depends on the hardware implementation.
**Solution**

To control the time of setting the device address, a new define `USBDEV_SET_ADDR_AFTER_STATUS` is introduced.
If `USBDEV_SET_ADDR_AFTER_STATUS` has the value 1 (default), the address is set in the USB device after the STATUS stage. Since this is the default, existing `periph_usbdev` drivers shouldn't be affected. Overwriting `USBDEV_SET_ADDR_AFTER_STATUS`  with 0 in `periph_cpu.h` or in driver header file let the address set directly after the SETUP stage.

### Testing procedure

Use `tests/usbus_cdc_ecm`:

For `stm32f723e-disco` the enumeration doesn't work at all without this PR and works reliable with this PR.
```
USEMODULE='periph_usbdev_hs_utmi' BOARD=stm32f723e-disco make -C tests/usbus_cdc_ecm flash
```
For any ESP32-S2 or ESP32-S3 board, the enumeration requires an addition reset cycle in every third or fourth enumeration without this PR and doesn't require any reset cycle with this PR.
```
BOARD=esp32s2-devkit make -C tests/usbus_cdc_ecm flash
```
Other platforms should still work with this PR, for example ATSAM platform:
```
BOARD=arduino-mkr1000 make -C tests/usbus_cdc_ecm flash
```

### Issues/PRs references


Co-authored-by: Gunar Schorcht <gunar@schorcht.net>
This commit is contained in:
bors[bot] 2023-04-16 15:33:53 +00:00 committed by GitHub
commit 1961274705
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 3 deletions

View File

@ -80,7 +80,7 @@
#include <stddef.h>
#include "assert.h"
#include "periph_cpu.h"
#include "periph_conf.h"
#include "usb.h"
#include "usb/usbopt.h"
@ -125,6 +125,20 @@ typedef struct usbdev_ep usbdev_ep_t;
*/
#define usbdev_ep_buf_t USBDEV_CPU_DMA_REQUIREMENTS uint8_t
/**
* @brief USBDEV specific requirement for setting the device address
*
* The address in the USB device can be set either directly after the SETUP
* stage on receipt of the `SET ADDRESS Request` or after the associated status
* stage. When the USB device address has to be set depends on the hardware.
* If `USBDEV_CPU_SET_ADDR_AFTER_STATUS` has the value 1 (default), the address
* is only set in the USB device after the status stage. Overwrite it with 0
* in `periph_cpu.h` to set the address already directly after the SETUP stage.
*/
#ifndef USBDEV_CPU_SET_ADDR_AFTER_STATUS
#define USBDEV_CPU_SET_ADDR_AFTER_STATUS 1
#endif
/**
* @brief Number of USB IN and OUT endpoints allocated
*

View File

@ -27,6 +27,14 @@
extern "C" {
#endif
/**
* @brief USB OTG peripheral requirement for setting the device address
*
* The address in the USB device has to be directly after the SETUP
* stage on receipt of the `SET ADDRESS Request`.
*/
#define USBDEV_CPU_SET_ADDR_AFTER_STATUS 0
/**
* @brief USB OTG peripheral type.
*

View File

@ -241,6 +241,10 @@ static int _recv_dev_setup(usbus_t *usbus, usb_setup_t *pkt)
case USB_SETUP_REQ_SET_ADDRESS:
DEBUG("usbus_control: Setting address\n");
usbus->addr = (uint8_t)pkt->value;
if (!USBDEV_CPU_SET_ADDR_AFTER_STATUS) {
usbdev_set(usbus->dev, USBOPT_ADDRESS, &usbus->addr,
sizeof(usbus->addr));
}
res = 1;
break;
case USB_SETUP_REQ_SET_CONFIGURATION:
@ -401,8 +405,10 @@ static int _handle_tr_complete(usbus_t *usbus,
case USBUS_CONTROL_REQUEST_STATE_INACK:
if (ep->dir == USB_EP_DIR_IN) {
if (usbus->addr && usbus->state == USBUS_STATE_RESET) {
usbdev_set(usbus->dev, USBOPT_ADDRESS, &usbus->addr,
sizeof(usbus->addr));
if (USBDEV_CPU_SET_ADDR_AFTER_STATUS) {
usbdev_set(usbus->dev, USBOPT_ADDRESS, &usbus->addr,
sizeof(usbus->addr));
}
/* Address configured */
usbus->state = USBUS_STATE_ADDR;
}