Anichang
Posts: 59
Joined: Tue Mar 23, 2021 5:49 pm

usb config, descriptors ... where's the doc?

Wed Jun 16, 2021 1:06 pm

USB is a wild animal by itself, and I can't tame it.

Every time I need to add CDCs I waste a lot of time to figure out a working descriptors combo by trial&error. Is there any doc to help configuring complex tinyusb configurations?

hippy
Posts: 10272
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: usb config, descriptors ... where's the doc?

Wed Jun 16, 2021 1:21 pm

I didn't find any docs myself. I got fed up creating different configurations by hand so wrote a Python program to generate them for me.

That's not complete yet so I haven't published it. If you can let me know what configuration you need I can look at seeing what I can produce for you.

One tip, if it's CDC's you are frequently changing, is to put the full quota as the last devices, then it's just a case of commenting and uncommenting, or using '#if' to include or exclude them as required.

Anichang
Posts: 59
Joined: Tue Mar 23, 2021 5:49 pm

Re: usb config, descriptors ... where's the doc?

Wed Jun 16, 2021 2:17 pm

hippy wrote:
Wed Jun 16, 2021 1:21 pm
I didn't find any docs myself. I got fed up creating different configurations by hand so wrote a Python program to generate them for me.

That's not complete yet so I haven't published it. If you can let me know what configuration you need I can look at seeing what I can produce for you.

One tip, if it's CDC's you are frequently changing, is to put the full quota as the last devices, then it's just a case of commenting and uncommenting, or using '#if' to include or exclude them as required.
Thanks for the tip but I don't understand what "full quota" is.

Let's take picoprobe code as an example; it is the thing I'm working on right now. I'm trying to add 1 CDC for UART0 (the existing code adds UART1) and 1 CDC for SUMP ( check out logic analyzer add on at https://github.com/perexg/picoprobe-sump ); a grand total of 3 CDCs and 1 vendor (probe) usb sub devices.
I increased the CFG_TUD_CDC from 1 to 3 in tusb_config.h; then in usb_descriptor.c:

- I changed the usb idProduct from ox0004 to ox0005 to work around windows registry cache (as I had already registered picoprobe vendorid 0x0004 before).
- the descriptors configuration follows:

Code: Select all

//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+

enum
{
  ITF_NUM_CDC_COM0,
  ITF_NUM_CDC_DATA0,
  ITF_NUM_CDC_COM1,
  ITF_NUM_CDC_DATA1,
  ITF_NUM_CDC_SUMP_COM,
  ITF_NUM_CDC_SUMP_DATA,
  ITF_NUM_PROBE,
  ITF_NUM_TOTAL
};

#define CDC_NOTIFICATION_EP_NUM0 0x81
#define CDC_DATA0_OUT_EP_NUM 0x02
#define CDC_DATA0_IN_EP_NUM 0x83
#define CDC_NOTIFICATION_EP_NUM1 0x84
#define CDC_DATA1_OUT_EP_NUM 0x05
#define CDC_DATA1_IN_EP_NUM 0x86
#define CDC_NOTIFICATION_EP_NUM2 0x87
#define CDC_SUMP_OUT_EP_NUM 0x08
#define CDC_SUMP_IN_EP_NUM 0x89
#define PROBE_OUT_EP_NUM 0x0a
#define PROBE_IN_EP_NUM 0x8b

#define CONFIG_TOTAL_LEN  (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_CDC_DESC_LEN + TUD_CDC_DESC_LEN + TUD_VENDOR_DESC_LEN)

uint8_t const desc_configuration[] =
{
  TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),

  // Interface 1 (uart0)
  TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_COM0, 0, CDC_NOTIFICATION_EP_NUM0, 64, CDC_DATA0_OUT_EP_NUM, CDC_DATA0_IN_EP_NUM, 64),

  // Interface 2 (uart1)
  TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_COM1, 0, CDC_NOTIFICATION_EP_NUM1, 64, CDC_DATA1_OUT_EP_NUM, CDC_DATA1_IN_EP_NUM, 64),

  // Interface 3 (SUMP)
  TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_SUMP_COM, 0, CDC_NOTIFICATION_EP_NUM2, 64, CDC_SUMP_OUT_EP_NUM, CDC_SUMP_IN_EP_NUM, 64),

  // Interface 4 (picoprobe)
  TUD_VENDOR_DESCRIPTOR(ITF_NUM_PROBE, 0, PROBE_OUT_EP_NUM, PROBE_IN_EP_NUM, 64)
};
This config seems to work as windows device manager reports 1 picoprobe (to be installed using zadig's libusb driver) and 3 com ports. I didn't import the SUMP code yet, so I can't confirm there's data moving correctly. But looks good so far.

But to figure out this config took me a long time, and that's not the first time. This time I've been banging my head on the CDC_NOTIFICATION_EP_NUMs; looks like windows wants a "notification" each CDC, but why not for the vendor sub device (probe)? And I've no idea what a "notification" is.

A couple of weeks ago I tried to place 8 CDCs (ie: as far as I understand it is the maximum, because each USB device has 16 endpoints max and each CDC needs 2 for rx+tx) and it was working on linux, without multiple "notification"s, up to 4 devices.

In general I've no idea what those addresses (0x81, 0x02, 0x83...) are, and the datasheet isn't helping much; there are long listings of EPs addresses but the names on the datasheet don't reflect the ones in code. I'm totally confused. Each time I've to configure the usb device I've to write pseudo-random text in usb_descriptors.c and hope it will work sooner than later.
Some guide lines to synthetize the usb beast would be highly appreciated. I mean, there are some good docs about USB, but they cover the huge complexity of USB; there's the need of a small doc with 10 commitments for the poor pico developer in need of USB.

Anichang
Posts: 59
Joined: Tue Mar 23, 2021 5:49 pm

Re: usb config, descriptors ... where's the doc?

Wed Jun 16, 2021 2:23 pm

Anichang wrote:
Wed Jun 16, 2021 2:17 pm
- the descriptors configuration follows:

Code: Select all

//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+

enum
{
  ITF_NUM_CDC_COM0,
  ITF_NUM_CDC_DATA0,
  ITF_NUM_CDC_COM1,
  ITF_NUM_CDC_DATA1,
  ITF_NUM_CDC_SUMP_COM,
  ITF_NUM_CDC_SUMP_DATA,
  ITF_NUM_PROBE,
  ITF_NUM_TOTAL
};

#define CDC_NOTIFICATION_EP_NUM0 0x81
#define CDC_DATA0_OUT_EP_NUM 0x02
#define CDC_DATA0_IN_EP_NUM 0x83
#define CDC_NOTIFICATION_EP_NUM1 0x84
#define CDC_DATA1_OUT_EP_NUM 0x05
#define CDC_DATA1_IN_EP_NUM 0x86
#define CDC_NOTIFICATION_EP_NUM2 0x87
#define CDC_SUMP_OUT_EP_NUM 0x08
#define CDC_SUMP_IN_EP_NUM 0x89
#define PROBE_OUT_EP_NUM 0x0a
#define PROBE_IN_EP_NUM 0x8b

#define CONFIG_TOTAL_LEN  (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_CDC_DESC_LEN + TUD_CDC_DESC_LEN + TUD_VENDOR_DESC_LEN)

uint8_t const desc_configuration[] =
{
  TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),

  // Interface 1 (uart0)
  TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_COM0, 0, CDC_NOTIFICATION_EP_NUM0, 64, CDC_DATA0_OUT_EP_NUM, CDC_DATA0_IN_EP_NUM, 64),

  // Interface 2 (uart1)
  TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_COM1, 0, CDC_NOTIFICATION_EP_NUM1, 64, CDC_DATA1_OUT_EP_NUM, CDC_DATA1_IN_EP_NUM, 64),

  // Interface 3 (SUMP)
  TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_SUMP_COM, 0, CDC_NOTIFICATION_EP_NUM2, 64, CDC_SUMP_OUT_EP_NUM, CDC_SUMP_IN_EP_NUM, 64),

  // Interface 4 (picoprobe)
  TUD_VENDOR_DESCRIPTOR(ITF_NUM_PROBE, 0, PROBE_OUT_EP_NUM, PROBE_IN_EP_NUM, 64)
};
This config seems to work as windows device manager reports 1 picoprobe (to be installed using zadig's libusb driver) and 3 com ports. I didn't import the SUMP code yet, so I can't confirm there's data moving correctly. But looks good so far.
Windows reads the interfaces as:
0: uart
2: uart
4: uart
6: probe

Even ids only. What about the odd ids? The spaghetti monster eat those? :)

hippy
Posts: 10272
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: usb config, descriptors ... where's the doc?

Wed Jun 16, 2021 5:46 pm

Anichang wrote:
Wed Jun 16, 2021 2:17 pm
A couple of weeks ago I tried to place 8 CDCs (ie: as far as I understand it is the maximum, because each USB device has 16 endpoints max and each CDC needs 2 for rx+tx) and it was working on linux, without multiple "notification"s, up to 4 devices.
I'll answer this one first. Each CDC has two endpoints; notification and a combined in and out.

There's also an endpoint used by 'Generic USB' so you have a maximum of 16 endpoints, one used by 'generic' leaving 15, divided by two allows up to 7 CDC interfaces, with one endpoint going unused.

But, while 16 is the maximum, there may be some definition which limits that to 9. That needs to be bumped to get access to more interfaces. No idea why it was set to 9 -

"#define CFG_TUD_EP_MAX" in '~/pico/pico-sdk/lib/tinyusb/src/device/usbd.c'
Anichang wrote:
Wed Jun 16, 2021 2:17 pm
This time I've been banging my head on the CDC_NOTIFICATION_EP_NUMs; looks like windows wants a "notification" each CDC, but why not for the vendor sub device (probe)? And I've no idea what a "notification" is.
Nor me. I don't know what notification really does or why VENDOR doesn't have one. I have never had to worry about that, never bothered to research it.
Anichang wrote:
Wed Jun 16, 2021 2:17 pm
In general I've no idea what those addresses (0x81, 0x02, 0x83...) are, and the datasheet isn't helping much; there are long listings of EPs addresses but the names on the datasheet don't reflect the ones in code. I'm totally confused.
All I have cared about is incrementing to a new endpoint number when one is needed, setting the msb or not when an endpoint is in, out or both. If I recall right; 0x8N is In, 0x0N is Out. That's got me by so far.

Fully understanding descriptors, endpoints, how they are defined, how many there are per interface, comes down to reading the USB specification or other datasheets which describe them; TinyUSB merely implements that specification, though the way that's done with TUD_xxx_DESCRIPTORS is TinyUSB specific.

I can't say I understand it beyond having a general appreciation for what's being done. That second field of TUD_xxxx_DESCRIPTOR is usually an index into the list of descriptors strings but I have not really understood when it is necessary, used or not, when it should be 0 or an index with a string.

As to other TUD_xxx_DESCRIPTOR fields I have simply looked at what others have done.

The way I learned what little I have was courtesy of Google and particularly looking at datasheets and application notes from microcontroller manufacturers which support USB. I'm afraid I don't have any particular recommendations to hand.

Bottom line is I don't think there's much alternative to the long hard slog until the light comes on, and it starts to gel. The good news is you don't have to know everything, just enough to get by.

One thing which does help is consistency, so where you have -

Code: Select all

#define CDC_NOTIFICATION_EP_NUM1 0x84
#define CDC_DATA1_OUT_EP_NUM 0x05
#define CDC_DATA1_IN_EP_NUM 0x86
I would change that first one to -

Code: Select all

#define CDC_DATA1_NOTIFICATION_EP_NUM 0x84
A tool which is really useful and readily to hand is 'sudo lsusb -v'. That details the descriptors of what's plugged into a Pi. You can narrow it down to your own device, replacing PID as appropriate, with ...

Code: Select all

sudo lsusb -v -d 2e8a:c803
One thing which confuses things is different naming conventions used in different places. Some people will have _CMD while others use _NOTIF for notification endpoints, some use _IN and _OUT while others will use a single _IN_OUT or _DATA. Some use TUD_xxx_DESCRIPTOR, others don't. It all makes it a PITA to merge one configuration with another.

The ordering of things within 'usb_descriptors.c' - 'tusb_ports.c' for MicroPython - is not how I would have it.

The definition of PID is also a nightmare; creates that caching problem you noted. I do it differently to allow more CDC.

All that is what drove me to write a program which generates the files to use.

This is what I have for 'usb_descriptors.c', 'tusb_ports.c' for my MicroPython build, which has descriptors for three CDC and the VENDOR thing. I number things incrementally and don't have any means of naming them at present, and while I know CDC works, I have never tested VENDOR -

Code: Select all

// ****************************************************************************
// *                                                                          *
// *    Auto-created by 'genusb'                                              *
// *                                                                          *
// ****************************************************************************
// *                                                                          *
// *    Interfaces : VENDOR, CDC x 3                                          *
// *                                                                          *
// ****************************************************************************

// The MIT License (MIT)
//
// Copyright 2021, "Hippy"
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

#include "tusb.h"
#include "pico/unique_id.h"
#include "pico/binary_info.h"

// ****************************************************************************
// *                                                                          *
// *    VID and PID Definitions                                               *
// *                                                                          *
// ****************************************************************************

// The default TinyUSB PID is -
//
//    01-- ---- --nv ihmc
//
// But we want to allow multiple CDC channels so we use -
//
//    11-- v-bn maih wccc
//         | || |||| | `------  CDC     3
//         | || |||| `--------  WEB
//         | || |||`----------  HID
//         | || ||`-----------  MIDI
//         | || |`------------  AUDIO
//         | || `-------------  MSC
//         | |`---------------  NET
//         | `----------------  BTH
//         `------------------  VENDOR  1

#define USBD_VID                (0x2E8A)

#define USBD_PID                ( 0xC000              + \
                                  PID_MAP(CDC,     0) + \
                                  PID_MAP(VENDOR, 11)   )

#define PID_MAP(itf, n)         ( (CFG_TUD_##itf) << (n) )

// ****************************************************************************
// *                                                                          *
// *    Binary Information for Picotool                                       *
// *                                                                          *
// ****************************************************************************

#define BI_GU_TAG               BINARY_INFO_MAKE_TAG('G', 'U')
#define BI_GU_ID                0x95639AC7
#define BI_GU_ITF(itf)          bi_decl(bi_string(BI_GU_TAG, BI_GU_ID, itf))

bi_decl(bi_program_feature_group_with_flags(
        BI_GU_TAG, BI_GU_ID, "genusb options",
        BI_NAMED_GROUP_SEPARATE_COMMAS | BI_NAMED_GROUP_SORT_ALPHA));

BI_GU_ITF("CDC x 3")
BI_GU_ITF("VENDOR")

// ****************************************************************************
// *                                                                          *
// *    USB Device Descriptor Strings                                         *
// *                                                                          *
// ****************************************************************************

enum {
    USBD_STR_LANGUAGE,          // 0
    USBD_STR_MANUFACTURER,      // 1
    USBD_STR_PRODUCT,           // 2
    USBD_STR_SERIAL_NUMBER,     // 3
    USBD_STR_CDC_0_NAME,        // 4
    USBD_STR_CDC_1_NAME,        // 5
    USBD_STR_CDC_2_NAME,        // 6
    USBD_STR_VENDOR_NAME,       // 7
};

char *const usbd_desc_str[] = {
    [USBD_STR_MANUFACTURER]     = "GenUsb",
    [USBD_STR_PRODUCT]          = "GenUsb-V-3C",
    [USBD_STR_SERIAL_NUMBER]    = NULL,
    [USBD_STR_CDC_0_NAME]       = "CDC0",
    [USBD_STR_CDC_1_NAME]       = "CDC1",
    [USBD_STR_CDC_2_NAME]       = "CDC2",
    [USBD_STR_VENDOR_NAME]      = "VENDOR",
};

// ****************************************************************************
// *                                                                          *
// *    Device Descriptor                                                     *
// *                                                                          *
// ****************************************************************************

static const tusb_desc_device_t usbd_desc_device = {
    .bLength                    = sizeof(tusb_desc_device_t),
    .bDescriptorType            = TUSB_DESC_DEVICE,
    .bcdUSB                     = 0x0210,
    .bDeviceClass               = TUSB_CLASS_MISC,
    .bDeviceSubClass            = MISC_SUBCLASS_COMMON,
    .bDeviceProtocol            = MISC_PROTOCOL_IAD,
    .bMaxPacketSize0            = CFG_TUD_ENDPOINT0_SIZE,
    .idVendor                   = USBD_VID,
    .idProduct                  = USBD_PID,
    .bcdDevice                  = 0x0100,
    .iManufacturer              = USBD_STR_MANUFACTURER,
    .iProduct                   = USBD_STR_PRODUCT,
    .iSerialNumber              = USBD_STR_SERIAL_NUMBER,
    .bNumConfigurations         = 1,
};

// ****************************************************************************
// *                                                                          *
// *    Endpoint Definitions                                                  *
// *                                                                          *
// ****************************************************************************

// .--------------------------------------------------------------------------.
// |    Virtual Serial Port                                                   |
// `--------------------------------------------------------------------------'

#define USBD_CDC_CMD_SIZE       (8)
#define USBD_CDC_DATA_SIZE      (64)

#define EPNUM_CDC_0_CMD         (0x81)
#define EPNUM_CDC_0_DATA        (0x82)

#define EPNUM_CDC_1_CMD         (0x83)
#define EPNUM_CDC_1_DATA        (0x84)

#define EPNUM_CDC_2_CMD         (0x85)
#define EPNUM_CDC_2_DATA        (0x86)

// .--------------------------------------------------------------------------.
// |    Vendor Commands                                                       |
// `--------------------------------------------------------------------------'

#define EPNUM_VENDOR_OUT        (0x07)
#define EPNUM_VENDOR_IN         (0x88)

// ****************************************************************************
// *                                                                          *
// *    Device Configuration                                                  *
// *                                                                          *
// ****************************************************************************

#define USBD_MAX_POWER_MA       (250)

#define USBD_DESC_LEN           ( (TUD_CONFIG_DESC_LEN                    ) + \
                                  (TUD_CDC_DESC_LEN       * CFG_TUD_CDC   ) + \
                                  (TUD_VENDOR_DESC_LEN    * CFG_TUD_VENDOR)   )

enum {
    ITF_NUM_CDC_0,  ITF_NUM_CDC_0_DATA,
    ITF_NUM_CDC_1,  ITF_NUM_CDC_1_DATA,
    ITF_NUM_CDC_2,  ITF_NUM_CDC_2_DATA,
    ITF_NUM_VENDOR,
    ITF_NUM_TOTAL
};

static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = {

    TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL,
                          USBD_STR_LANGUAGE,
                          USBD_DESC_LEN,
                          TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
                          USBD_MAX_POWER_MA),

    TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0,
                      USBD_STR_CDC_0_NAME,
                         EPNUM_CDC_0_CMD, USBD_CDC_CMD_SIZE,
                         EPNUM_CDC_0_DATA & 0x7F,
                         EPNUM_CDC_0_DATA, USBD_CDC_DATA_SIZE),

    TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1,
                      USBD_STR_CDC_1_NAME,
                         EPNUM_CDC_1_CMD, USBD_CDC_CMD_SIZE,
                         EPNUM_CDC_1_DATA & 0x7F,
                         EPNUM_CDC_1_DATA, USBD_CDC_DATA_SIZE),

    TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_2,
                      USBD_STR_CDC_2_NAME,
                         EPNUM_CDC_2_CMD, USBD_CDC_CMD_SIZE,
                         EPNUM_CDC_2_DATA & 0x7F,
                         EPNUM_CDC_2_DATA, USBD_CDC_DATA_SIZE),

    TUD_VENDOR_DESCRIPTOR(ITF_NUM_VENDOR,
                         USBD_STR_VENDOR_NAME,
                            EPNUM_VENDOR_OUT & 0x7F,
                            EPNUM_VENDOR_IN, CFG_TUD_VENDOR_TX_BUFSIZE),

};

// ****************************************************************************
// *                                                                          *
// *    USB Device Callbacks                                                  *
// *                                                                          *
// ****************************************************************************

const uint8_t *tud_descriptor_device_cb(void) {
    return (const uint8_t *)&usbd_desc_device;
}

const uint8_t *tud_descriptor_configuration_cb(uint8_t index) {
    (void)index;
    return usbd_desc_cfg;
}

const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
    #define DESC_STR_MAX_LENGTH (20)
    static uint16_t desc_str[DESC_STR_MAX_LENGTH];

    uint8_t len;
    if (index == USBD_STR_LANGUAGE) {
        desc_str[1] = 0x0409; // Supported language is English
        len = 1;
    } else {
        if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) {
            return NULL;
        }
        if (index == USBD_STR_SERIAL_NUMBER) {
            pico_unique_board_id_t id;
            pico_get_unique_board_id(&id);
            // byte by byte conversion
            for (len = 0; len < 16; len += 2) {
                const char *hexdig = "0123456789ABCDEF";
                desc_str[1 + len + 0] = hexdig[id.id[len >> 1] >> 4];
                desc_str[1 + len + 1] = hexdig[id.id[len >> 1] & 0x0F];
            }
        } else {
            const char *str = usbd_desc_str[index];
            for (len = 0; len < DESC_STR_MAX_LENGTH - 1 && str[len]; ++len) {
                desc_str[1 + len] = str[len];
            }
        }
    }

    // first byte is length (including header), second byte is string type
    desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * len + 2);

    return desc_str;
}

WestfW
Posts: 96
Joined: Tue Nov 01, 2011 9:56 pm

Re: usb config, descriptors ... where's the doc?

Wed Jun 16, 2021 11:37 pm

This time I've been banging my head on the CDC_NOTIFICATION_EP_NUMs; looks like windows wants a "notification" each CDC, but why not for the vendor sub device (probe)? And I've no idea what a "notification" is.
This is USB-defined stuff, not Pico or TinyUSB specific. See perhaps https://www.beyondlogic.org/usbnutshell/usb1.shtml or https://www.ftdichip.com/Support/Docume ... xample.htm

Each CDC uses three "endpoints" - a "control" endpoint (bi-directional-ish?) and two bulk data endpoints (or "one bidirectional endpoint.")
Not all devices have the data endpoints; a HID device does all of its communicating over the control endpoint. I believe that the probe is implemented as a HID. Library-level stuff on the host can read and write to HID devices. Looking at the definition of TUD_CDC_DESCRIPTOR in usbd.h might be "interesting" - it explicitly mentions

So you see only "even" endpoints because either the control or data endpoints aren't shown (being part of "the same device.") If you put the probe first, you should see only the odd endpoints, I think. It explicitly mentions every "interface" and "endpoint."
I tried to place 8 CDCs (ie: as far as I understand it is the maximum, because each USB device has 16 endpoints max and each CDC needs 2 for rx+tx)
You have to be careful about whether a device spec is talking about "endpoints" or "bi-directional endpoints." The rp2040 datasheet says "• Supports up to 32 endpoints (Endpoints 0 → 15 in both in and out directions)" So there should be plenty for 8 CDCs. (OTOH, a USB device needs a separate "endpoint 0", so you couldn't do a full 16 CDCs.)

Windows reads the interfaces as:
0: uart
2: uart
4: uart
How are you getting windows to show you that? I've been working on the Adafruit Arduino TinyUSB library to add multiple CDC support (to non-Pico devices), and I've had a hard time getting either Mac or Windows to show me any information about the finer structure of USB devices (below the "device" level.) I have the three CDC interfaces (and they work!):

Code: Select all

ls -l /dev/tty.*
crw-rw-rw-  1 wheel   20, 0x000002fe Jun 16 16:33 /dev/tty.usbmodem147111
crw-rw-rw-  1 wheel   20, 0x00000300 Jun 16 16:33 /dev/tty.usbmodem147113
crw-rw-rw-  1 wheel   20, 0x00000302 Jun 16 16:33 /dev/tty.usbmodem147115
(heh - odd numbers!)
but the closest thing I have to lsusb only shows:

Code: Select all

                Metro M0 Express:

                  Product ID: 0x8013
                  Vendor ID: 0x239a
                  Version: 1.00
                  Serial Number: 83A96D66504A5230352E3120FF031A26
                  Speed: Up to 12 Mb/sec
                  Manufacturer: Adafruit
                  Location ID: 0x14711000 / 25
                  Current Available (mA): 500
                  Current Required (mA): 100
                  Extra Operating Current (mA): 0

Anichang
Posts: 59
Joined: Tue Mar 23, 2021 5:49 pm

Re: usb config, descriptors ... where's the doc?

Wed Jun 16, 2021 11:55 pm

hippy wrote:
Wed Jun 16, 2021 5:46 pm
But, while 16 is the maximum, there may be some definition which limits that to 9. That needs to be bumped to get access to more interfaces. No idea why it was set to 9 -

"#define CFG_TUD_EP_MAX" in '~/pico/pico-sdk/lib/tinyusb/src/device/usbd.c'
Thanks to this I've been able to get 6 CDCs + 1 VENDOR running. And in general it is more clear what to do. Thanks

hippy
Posts: 10272
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: usb config, descriptors ... where's the doc?

Mon Jun 21, 2021 1:51 pm

Anichang wrote:
Wed Jun 16, 2021 11:55 pm
Thanks to this I've been able to get 6 CDCs + 1 VENDOR running. And in general it is more clear what to do. Thanks
Excellent news.

One quick question; what software tools are you using to send and receive vendor packets ?

User avatar
triss64738
Posts: 31
Joined: Wed Jun 16, 2021 5:13 pm
Location: masto/fedi: sys64738@hellsite.site
Contact: Website

Re: usb config, descriptors ... where's the doc?

Mon Jun 21, 2021 2:39 pm

libusb? (+ a wrapper maybe for your preferred language)

jamesh
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 29024
Joined: Sat Jul 30, 2011 7:41 pm

Re: usb config, descriptors ... where's the doc?

Mon Jun 21, 2021 2:56 pm

triss64738 wrote:
Mon Jun 21, 2021 2:39 pm
libusb? (+ a wrapper maybe for your preferred language)
That's a linux library, not available on the Pico.
Principal Software Engineer at Raspberry Pi (Trading) Ltd.
Working in the Application's Team.

hippy
Posts: 10272
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: usb config, descriptors ... where's the doc?

Mon Jun 21, 2021 3:15 pm

I wasn't clear but it is Pi-side I need the library code or tools for - Something so I can confirm I can send from the Pi and get something back, help me get Pico receive, send, and the inevitable echo, working.

I am sure 'libusb' will do everything I need - and I have 'PyUsb' identifying my USB devices - but that doesn't help in figuring out how to send and receive vendor packets. I was hoping there were some ready-rolled apps - vendorsend "hello" - or similar, or examples which show how to do it with 'libusb' or 'PyUsb'.

I did spend some time Googling but VID and related topics pretty much bury anything related to vendor packets.

I was hoping someone who was actually using vendor packets would have tools to test that and would be kind enough to tell us what they were using to prove things work.

User avatar
triss64738
Posts: 31
Joined: Wed Jun 16, 2021 5:13 pm
Location: masto/fedi: sys64738@hellsite.site
Contact: Website

Re: usb config, descriptors ... where's the doc?

Mon Jun 21, 2021 3:27 pm

After reading the picotool source, I think the function you need is libusb_bulk_transfer (after setting up & claiming the device stuff, see a bit higher up in that source file), it lets you send and receive raw bytes to/from a specified endpoint, which I guess is what you want/need for vendor interfaces. For Python, I don't really now, but I guess you can try to figure out which wrapper functions call these underlying ones. Depends on how thin/thick the wrapper is, I guess.

Anichang
Posts: 59
Joined: Tue Mar 23, 2021 5:49 pm

Re: usb config, descriptors ... where's the doc?

Tue Jun 22, 2021 6:35 am

hippy wrote:
Mon Jun 21, 2021 3:15 pm
I wasn't clear but it is Pi-side I need the library code or tools for - Something so I can confirm I can send from the Pi and get something back, help me get Pico receive, send, and the inevitable echo, working.

I am sure 'libusb' will do everything I need - and I have 'PyUsb' identifying my USB devices - but that doesn't help in figuring out how to send and receive vendor packets. I was hoping there were some ready-rolled apps - vendorsend "hello" - or similar, or examples which show how to do it with 'libusb' or 'PyUsb'.

I did spend some time Googling but VID and related topics pretty much bury anything related to vendor packets.

I was hoping someone who was actually using vendor packets would have tools to test that and would be kind enough to tell us what they were using to prove things work.
Currently I just refactored probe.h and probe.c from picoprobe's code (see on github), in order to have it working along my own code. I don't exactly know what probe.c does, but I've spotted tud_vendor_write() or alike, so I suppose all the code you need pico-side is already in tinyusb. On the other side I have libusb on linux and zadig installing a libusb windows binary driver for the pico device.

In theory - and I don't know much - the vendor endpoint limits itself to rx/tx usb raw frames for custom ("vendor") operations later on. So you don't need any driver in order to access raw transfers. It is 1 single endpoint, this means device has no way to start a transfer; it relies on USB polling nature. Basically each N microseconds (1000 for USB1.1, 125 for USB2.0, less for USB3.0) the master goes asking for data and in the case of vendor endpoint, it gets raw data and pass it to the app currently using the device.

Return to “SDK”