Secondary serial port

Status
Not open for further replies.

kk_omnisys

New member
Hello everyone,

In my project I need two communication channels between my PC and my Teensy (3.6).

I need them separated into Serial and SerialX streams since they will be addressed from different GUIs on the PC.

My Teensy enumerates as Teensy Dual and one Serial port look like its working in windows device manager, but the composite usb device and second usb port has the exclamation mark and errors in their status.

My Google-Fu might be too weak, but this is what I got around the forum
https://forum.pjrc.com/threads/34610-Multiple-CDC-on-Teensy-3-1-3-2

and readme headers in the .h / .c teensy files.

Hijack the USB_MIDI_SERIAL definition in usb_desc.h (copy to sketch folder so I do not overwrite for all projects)

Code:
#elif defined(USB_MIDI_SERIAL)
	#define VENDOR_ID		0x16C0
	#define PRODUCT_ID		0x048A
	#define MANUFACTURER_NAME	{'T','e','e','n','s','y','d','u','i','n','o'}
	#define MANUFACTURER_NAME_LEN	11
	#define PRODUCT_NAME		{'T','e','e','n','s','y',' ','D','u','a','l'}
	#define PRODUCT_NAME_LEN	11

	#define EP0_SIZE				64
	#define NUM_ENDPOINTS        	6
	#define NUM_USB_BUFFERS			30
	#define NUM_INTERFACE			4

	#define CDC_IAD_DESCRIPTOR		1

	#define CDC_STATUS_INTERFACE	0
	
	#define CDC_DATA_INTERFACE		1	// Serial
	
	#define CDC_ACM_ENDPOINT		1
	#define CDC_RX_ENDPOINT       	2
	#define CDC_TX_ENDPOINT       	3
	#define CDC_ACM_SIZE          	16
	#define CDC_RX_SIZE           	64
	#define CDC_TX_SIZE           	64

	#define CDC_STATUS_INTERFACE2	2
	#define CDC_DATA_INTERFACE2		3	// Serial 2
	
	#define CDC_ACM2_ENDPOINT		4
	#define CDC_RX2_ENDPOINT       	5
	#define CDC_TX2_ENDPOINT       	6
	#define CDC_ACM2_SIZE          	16
	#define CDC_RX2_SIZE           	64
	#define CDC_TX2_SIZE           	64
  
  
	// CDC_ACM_ENDPOINT
	#define ENDPOINT1_CONFIG		ENDPOINT_TRANSIMIT_ONLY

	// CDC_RX_ENDPOINT
	#define ENDPOINT2_CONFIG		ENDPOINT_RECEIVE_ONLY

	// CDC_TX_ENDPOINT
	#define ENDPOINT3_CONFIG		ENDPOINT_TRANSIMIT_ONLY

	// CDC_ACM2_ENDPOINT
	#define ENDPOINT4_CONFIG		ENDPOINT_TRANSIMIT_ONLY

	// CDC_RX2_ENDPOINT
	#define ENDPOINT5_CONFIG		ENDPOINT_RECEIVE_ONLY
	
	// CDC_TX2_ENDPOINT
	#define ENDPOINT6_CONFIG		ENDPOINT_TRANSIMIT_ONLY
	
#endif

In usb_desc.c, create new section for our CONFIG_DESC_SIZE for the secondary CDC
Code:
#define CDC_DATA_INTERFACE2_DESC_POS	CDC_DATA_INTERFACE_DESC_POS+CDC_DATA_INTERFACE_DESC_SIZE
#ifdef  CDC_DATA_INTERFACE2
#define CDC_DATA_INTERFACE2_DESC_SIZE	9+5+5+4+5+7+9+7+7
#else
#define CDC_DATA_INTERFACE2_DESC_SIZE	0
#endif

and its corresponding config_descriptor section
Code:
#ifdef CDC_DATA_INTERFACE2
        // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
        9,                                      // bLength
        4,                                      // bDescriptorType
        CDC_STATUS_INTERFACE2,					// bInterfaceNumber
        0,                                      // bAlternateSetting
        1,                                      // bNumEndpoints
        0x02,                                   // bInterfaceClass
        0x02,                                   // bInterfaceSubClass
        0x01,                                   // bInterfaceProtocol
        0,                                      // iInterface
        // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26
        5,                                      // bFunctionLength
        0x24,                                   // bDescriptorType
        0x00,                                   // bDescriptorSubtype
        0x10, 0x01,                             // bcdCDC
        // Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27
        5,                                      // bFunctionLength
        0x24,                                   // bDescriptorType
        0x01,                                   // bDescriptorSubtype
        0x01,                                   // bmCapabilities
        1,                                      // bDataInterface
        // Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28
        4,                                      // bFunctionLength
        0x24,                                   // bDescriptorType
        0x02,                                   // bDescriptorSubtype
        0x06,                                   // bmCapabilities
        // Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33
        5,                                      // bFunctionLength
        0x24,                                   // bDescriptorType
        0x06,                                   // bDescriptorSubtype
        CDC_STATUS_INTERFACE2,                   // bMasterInterface
        CDC_DATA_INTERFACE2,                     // bSlaveInterface0
        // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
        7,                                      // bLength
        5,                                      // bDescriptorType
        CDC_ACM2_ENDPOINT | 0x80,                // bEndpointAddress
        0x03,                                   // bmAttributes (0x03=intr)
        CDC_ACM2_SIZE, 0,                        // wMaxPacketSize
        64,                                     // bInterval
        // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
        9,                                      // bLength
        4,                                      // bDescriptorType
        CDC_DATA_INTERFACE2,                     // bInterfaceNumber
        0,                                      // bAlternateSetting
        2,                                      // bNumEndpoints
        0x0A,                                   // bInterfaceClass
        0x00,                                   // bInterfaceSubClass
        0x00,                                   // bInterfaceProtocol
        0,                                      // iInterface
        // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
        7,                                      // bLength
        5,                                      // bDescriptorType
        CDC_RX2_ENDPOINT,                        // bEndpointAddress
        0x02,                                   // bmAttributes (0x02=bulk)
        CDC_RX2_SIZE, 0,                         // wMaxPacketSize
        0,                                      // bInterval
        // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
        7,                                      // bLength
        5,                                      // bDescriptorType
        CDC_TX2_ENDPOINT | 0x80,                 // bEndpointAddress
        0x02,                                   // bmAttributes (0x02=bulk)
        CDC_TX2_SIZE, 0,                         // wMaxPacketSize
        0,                                      // bInterval
#endif // CDC_DATA_INTERFACE2

and in usb_serial.c and usb_serial.h I copy-paste each function with pointers to the new endpoints

Code:
int usb_serial_getchar2(void)
{
	unsigned int i;
	int c;

	if (!rx_packet) {
		if (!usb_configuration) return -1;
		rx_packet = usb_rx(CDC_RX2_ENDPOINT);
		if (!rx_packet) return -1;
	}
	i = rx_packet->index;
	c = rx_packet->buf[i++];
	if (i >= rx_packet->len) {
		usb_free(rx_packet);
		rx_packet = NULL;
	} else {
		rx_packet->index = i;
	}
	return c;
}

I see that there are more files in hardware\teensy\avr\cores, but I'm no sure where to edit. Anybody else have some success with the CDCs?

Best regards
 

Attachments

  • usb_desc.c
    22.2 KB · Views: 64
  • usb_desc.h
    7.8 KB · Views: 66
  • usb_dev.c
    30.2 KB · Views: 74
  • usb_dev.h
    4.4 KB · Views: 63
  • usb_inst.cpp
    2.4 KB · Views: 65
  • usb_serial.c
    12.8 KB · Views: 77
  • usb_serial.h
    10.5 KB · Views: 66
Thanks for the reply Paul, that did the trick.

I now have two USB serial devices enumerated in the device manager.

I now continue with usb_serial.c and usb_serial.h.

I expose my secondary functions in the .h file by adding

Code:
class usb_serial_class : public Stream
{
public:
	constexpr usb_serial_class() {}
        virtual int available2() { return usb_serial_available2(); }
 ...

But cannot access it during compile:
Code:
GSE_Teensy:379: error: 'class usb_serial_class' has no member named 'available2'
  if(Serial.available2()>=1){

            ^

Is it because stream does not have "available()" or something?

Best regards
 
It turns out that it is difficult to know if the compiler uses the files from the cores directory or the files local to the sketch directory.
I did not want to modify the original teensy core files so I try to place them under the local sketch.

I placed my modified usb_desc.c, usb_desc.h, usb_dev.c, usb_dev.h, usb_inst.cpp in the sketch directory.

The new usb_serial2.c and usb_serial2.h are also placed in the sketch directory.

If someone wants to try them out I can post them with an example sketch
 
@kk_omnisys I was looking for this exact setup. It would make adding a debug channel or secondary programming channel so much easier for my use case.
Did you publish your changes to GitHub or anywhere?
Would love to take a look at what you've done to save re-inventing the wheel.
@PaulStoffregen It would actually be really nice if this was part of TeensyDunio as a USB Type board option (Dual Serial) published as Serial and USBSerial2 or Serial7 maybe?
 
Status
Not open for further replies.
Back
Top