Using USB2 on Teensy 3.6

Status
Not open for further replies.

bghiorso

Member
I have no experience using the Teensy for USB. Mostly I've used it for digital I/O and logic.
I need to send/receive short (<40 chars) command style ascii strings to/from a digital motor controller that only talks when addressed.
The controller generally responds within milliseconds of receiving a command. (57600 baud 8 bits 2 stop bits no parity)
The needed functionality is similar to having a conversation with Tera Term or some such emulator except that the Teensy would be sending the commands to the controller. I can do fairly elaborate control routines using LabView and similar programs, but for this application I need an embedded control box with I/O and unconnected to any computer.
I would like to do this using the USB2 port on the Teensy so the main port is available as usual for program development.
I have looked at the library USBHost_t36 but I don't know how to use this for my simple application.
Any guidance or examples would be appreciated.
Thanks,
Bill
 
I am using a USB to RS485 adapter which is wired to the motor so it is convenient to plug this into the Teensy. I am using the Tall Dog breakout board Standard version A2 with the socket attached to the USB2 port
 
Again not fully knowing your setup.

You can setup a host USB connector to the T3.6.

The simplest way to try it out is using the USB Host cable: https://www.pjrc.com/store/cable_usb_host_t36.html And of course the talldog setup should work as well.

We have a USBHost_t36 library that works with T3.6 and T4.x boards to communicate with some USB devices. We do have support for several USB to Serial adapters. Not sure if we we have full support for your RS485 device or not. But you could try one of the example sketches like the Serial test to see if it knows your device or not. If not it may be as easy as adding a VID/PID pair to table (Vendor ID/Product ID). Of may need to debug...

Or potentially you might be able to use an TTL to RS485 like adapter to one of the hardware Serial ports.
 
So I ran the SerialTest example with the USB-to-485 adapter attached to the Tall Dog USB port and got the following output in the serial monitor:

USB Host Testing - Serial
*** Device USERIAL1 10c4:ea60 - connected ***
manufacturer: Silicon Labs
product: CP2102 USB to UART Bridge Controller

When I disconnected it I got:

*** Device USERIAL1 - disconnected ***

And reconnected it again:

*** Device USERIAL1 10c4:ea60 - connected ***
manufacturer: Silicon Labs
product: CP2102 USB to UART Bridge Controller

So I assume that this is a supported device.

The communications settings for my device are 57600 Baud, 8 bits, no parity, no flow control, 2 stop bits.
The baud rate could be slower if necessary.
I would prefer to use the 2nd USB port on the T3.6 with the 485 adapter shown above if it's not to involved.

What I'm looking for is an example of how to send a short text string to the device such as:
@18 11 12 78654<cr>
to which the device responds within milliseconds with:
* 12<cr>
which I need to be able to read.

If there is some (hopefully) not-too-complex way to do this it would be great.
Thanks for your (patient!) help...
Bill
 
Unless using that USB-RS485 adaptor is a hard requirement, I believe you should consider connecting a RS485 adaptor directly to one of the hardware serial ports. Many RS-485 protocols can be sensitive to latency. You'll get the lowest latency using a hardware serial port. Various USB-Serial adaptors add latency, which can vary depending on the adaptor and sometimes even the data itself.

Either way, you use either print() or write() with the port name to transmit data.

So if you use Serial2 (connecting the TTL level serial signals to RX2 & TX2) you would use Serial2.write() to transmit. If you use USBHost_t36, you choose the port name when you create the instance in your code. In the SerialTest example, the name is "userial" because of this line:

Code:
USBSerial userial(myusb);  // works only for those Serial devices who transfer <=64 bytes (like T3.x, FTDI...

So to send @18 11 12 78654<cr>, you would use either this:

Code:
Serial2.print("@18 11 12 78654\r");

or this:

Code:
userial.print("@18 11 12 78654\r");

Likewise, receiving data is done with available() to check if data has arrived and read() to fetch the data. The functions you use work the same way regardless of hardware serial versus USBHost_t36.

But hardware serial avoids the extra latency of USB, so you're probably better off using hardware serial if you can.
 
Thank you Kurt and Paul for your help on this issue.
I have some working test code below that accepts text from TeraTerm and echoes it back when it sees a \r terminator.
The only issue I've had is that I haven't been able to set the baud rate at 57600 - it's currently stuck at 115200.
Thanks again for your help!
Bill


Code:
//TEENSY36_SERIAL_TEST_RECEIVE V3
#include "USBHost_t36.h"
#define USBBAUD 57600
uint32_t baud = USBBAUD;
uint32_t format = USBHOST_SERIAL_8N2;
USBHost myusb;


USBSerial userial(myusb); //only for those Serial devices that transfer <= 64 bytes like T3.6, FTDI, etc...


USBDriver *drivers[] = {&userial};
#define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0]))


const char * driver_names[CNT_DEVICES] = {"USERIAL1" };


bool driver_active[CNT_DEVICES] = {true};


int count = 0;
int ontime1 = 500;
int ontime2 = 200;
int ontime3 = 1000;
int incomingByte = 0;
String inputstring;


void setup() {
  // put your setup code here, to run once:
   pinMode(13, OUTPUT);
   digitalWrite(13, HIGH);
   delay(ontime2);
   digitalWrite(13, LOW);
   delay(ontime3);
  
   myusb.begin();
   userial.begin(57600,format);
   userial.setTimeout(5000);


}


void loop() {
  // read text from TeraTerm and echo after \r
    if (userial.available() > 0) {
      userial.println();
      inputstring = userial.readStringUntil(13);
      userial.print(inputstring);
    }
}
 
I wanted to ask again about changing the baud rate from the default(?) 115200 to 57600. I have not been able to change this with the existing settings in the test program, so I guess I'm doing something wrong here...
Thanks,
Bill
 
AFAIK
USB serial does not support fixed baud rate it always goes with max speed.
suggest to follow Paul's suggestion and to use real HWSerial, where you must set speed
 
The only issue I've had is that I haven't been able to set the baud rate at 57600 - it's currently stuck at 115200.

Very likely a bug in the USBHost_t36 library's driver for CP2102. :(


USB serial does not support fixed baud rate it always goes with max speed.

This is USB host. Indeed the actual communication between Teensy and CP2102 is at the USB native speed. But the USBSerial::begin() function in USBHost_t36 is supposed to send a control message to the CP2102 (or whatever supported USB serial device it detected) to tell it to use the baud rate you want. Thereafter, it is the CP2102's job to receive at USB native speed and relay the bytes as hardware serial at the requested baud rate.

For USB device, Serial.begin() completely ignores whatever number you give. The usage model is exactly the same. The USB host sends the requested baud rate, which Teensy can access with Serial.baud(), but all actual data transfer over USB happens as USB native speed (12 or 480 Mbit/sec, minus protocol overhead & USB's flow control). We're all used to the idea that Serial.begin(baud) ignores whatever number you use. That's only true for USB device, because the host side specifies the baud rate and the device's role is to do the host's bidding!
 
There may be an order issue on when the begin method is called.

Maybe try it like:
Code:
//TEENSY36_SERIAL_TEST_RECEIVE V3
#include "USBHost_t36.h"
#define USBBAUD 57600
uint32_t baud = USBBAUD;
uint32_t format = USBHOST_SERIAL_8N2;
USBHost myusb;


USBSerial userial(myusb); //only for those Serial devices that transfer <= 64 bytes like T3.6, FTDI, etc...


USBDriver *drivers[] = {&userial};
#define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0]))


const char * driver_names[CNT_DEVICES] = {"USERIAL1" };


bool driver_active[CNT_DEVICES] = {true};


int count = 0;
int ontime1 = 500;
int ontime2 = 200;
int ontime3 = 1000;
int incomingByte = 0;
String inputstring;


void setup() {
  // put your setup code here, to run once:
   pinMode(13, OUTPUT);
   digitalWrite(13, HIGH);
   delay(ontime2);
   digitalWrite(13, LOW);
   delay(ontime3);
  
   myusb.begin();
   userial.begin(57600,format);
   userial.setTimeout(5000);


}

[COLOR="#FF0000"]bool userial_prev = false;[/COLOR]

void loop() {
[COLOR="#FF0000"]    if (userial && !userial_prev) {
        userial.begin(USBBAUD ,format);
    }
    userial_prev = userial;  // remember the current state of being connected. 
        
[/COLOR]
  // read text from TeraTerm and echo after \r
    if (userial.available() > 0) {
      userial.println();
      inputstring = userial.readStringUntil(13);
      userial.print(inputstring);
    }
}

Note: typed in on the fly so...
 
Hi Kurt,
yes this DOES fix the problem, though I'm not sure what you're doing here.
Does this reload the settings so they are not "forgotten" for every pass through the loop?
Or can this be done only once?
In any case I'll try to add the actual program into this loop and see how it goes...
Many thanks to you and Paul for all the help. You've put me on track again!
Bill
 
As it reads:

Any time it enters loop and userial is present, AND it was not present during the last loop - it will redo the begin settings.

> If userial stays offline - nothing happens

> If userial appears and stays present loop to loop - nothing happens
 
@defragster and @bghiorso - yes that is what is happening. When the USB Serial device is connected it defaults to a serial baud rate, only when you call the begin method after the connection has completed do we actually process the baud rate...

The code could (and maybe should) probably be changed to default to the last used baud rate. Would not be that much of a change to the code, but would then need to retest with a few different Serial adapters to make sure did not screw up anything...

Will see if I get inspired to do so. But the current solution should hopefully work for now.
 
Status
Not open for further replies.
Back
Top